]>
Commit | Line | Data |
---|---|---|
b58b1157 | 1 | /* Callgraph based intraprocedural optimizations. |
a4de48bc | 2 | Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. |
1c4a429a JH |
3 | Contributed by Jan Hubicka |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify it under | |
8 | the terms of the GNU General Public License as published by the Free | |
9 | Software Foundation; either version 2, or (at your option) any later | |
10 | version. | |
11 | ||
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GCC; see the file COPYING. If not, write to the Free | |
19 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |
20 | 02111-1307, USA. */ | |
21 | ||
18c6ada9 JH |
22 | /* This module implements main driver of compilation process as well as |
23 | few basic intraprocedural optimizers. | |
24 | ||
25 | The main scope of this file is to act as an interface in between | |
26 | tree based frontends and the backend (and middle end) | |
27 | ||
28 | The front-end is supposed to use following functionality: | |
29 | ||
30 | - cgraph_finalize_function | |
31 | ||
32 | This function is called once front-end has parsed whole body of function | |
33 | and it is certain that the function body nor the declaration will change. | |
34 | ||
35 | (There is one exception needed for implementing GCC extern inline function.) | |
36 | ||
37 | - cgraph_varpool_finalize_variable | |
38 | ||
1ae58c30 | 39 | This function has same behavior as the above but is used for static |
18c6ada9 JH |
40 | variables. |
41 | ||
42 | - cgraph_finalize_compilation_unit | |
43 | ||
44 | This function is called once compilation unit is finalized and it will | |
45 | no longer change. | |
46 | ||
47 | In the unit-at-a-time the call-graph construction and local function | |
48 | analysis takes place here. Bodies of unreachable functions are released | |
49 | to conserve memory usage. | |
50 | ||
51 | ??? The compilation unit in this point of view should be compilation | |
52 | unit as defined by the language - for instance C frontend allows multiple | |
53 | compilation units to be parsed at once and it should call function each | |
54 | time parsing is done so we save memory. | |
55 | ||
56 | - cgraph_optimize | |
57 | ||
58 | In this unit-at-a-time compilation the intra procedural analysis takes | |
59 | place here. In particular the static functions whose address is never | |
60 | taken are marked as local. Backend can then use this information to | |
61 | modify calling conventions, do better inlining or similar optimizations. | |
62 | ||
63 | - cgraph_assemble_pending_functions | |
64 | - cgraph_varpool_assemble_pending_variables | |
65 | ||
66 | In non-unit-at-a-time mode these functions can be used to force compilation | |
67 | of functions or variables that are known to be needed at given stage | |
68 | of compilation | |
69 | ||
70 | - cgraph_mark_needed_node | |
71 | - cgraph_varpool_mark_needed_node | |
72 | ||
73 | When function or variable is referenced by some hidden way (for instance | |
74 | via assembly code and marked by attribute "used"), the call-graph data structure | |
75 | must be updated accordingly by this function. | |
76 | ||
77 | - analyze_expr callback | |
78 | ||
79 | This function is responsible for lowering tree nodes not understood by | |
80 | generic code into understandable ones or alternatively marking | |
81 | callgraph and varpool nodes referenced by the as needed. | |
82 | ||
83 | ??? On the tree-ssa genericizing should take place here and we will avoid | |
84 | need for these hooks (replacing them by genericizing hook) | |
85 | ||
86 | - expand_function callback | |
87 | ||
88 | This function is used to expand function and pass it into RTL back-end. | |
89 | Front-end should not make any assumptions about when this function can be | |
90 | called. In particular cgraph_assemble_pending_functions, | |
91 | cgraph_varpool_assemble_pending_variables, cgraph_finalize_function, | |
92 | cgraph_varpool_finalize_function, cgraph_optimize can cause arbitrarily | |
93 | previously finalized functions to be expanded. | |
94 | ||
95 | We implement two compilation modes. | |
96 | ||
97 | - unit-at-a-time: In this mode analyzing of all functions is deferred | |
98 | to cgraph_finalize_compilation_unit and expansion into cgraph_optimize. | |
99 | ||
100 | In cgraph_finalize_compilation_unit the reachable functions are | |
101 | analyzed. During analysis the call-graph edges from reachable | |
102 | functions are constructed and their destinations are marked as | |
103 | reachable. References to functions and variables are discovered too | |
104 | and variables found to be needed output to the assembly file. Via | |
105 | mark_referenced call in assemble_variable functions referenced by | |
106 | static variables are noticed too. | |
107 | ||
e1990f69 | 108 | The intra-procedural information is produced and its existence |
18c6ada9 JH |
109 | indicated by global_info_ready. Once this flag is set it is impossible |
110 | to change function from !reachable to reachable and thus | |
111 | assemble_variable no longer call mark_referenced. | |
112 | ||
113 | Finally the call-graph is topologically sorted and all reachable functions | |
114 | that has not been completely inlined or are not external are output. | |
115 | ||
116 | ??? It is possible that reference to function or variable is optimized | |
117 | out. We can not deal with this nicely because topological order is not | |
118 | suitable for it. For tree-ssa we may consider another pass doing | |
119 | optimization and re-discovering reachable functions. | |
120 | ||
121 | ??? Reorganize code so variables are output very last and only if they | |
122 | really has been referenced by produced code, so we catch more cases | |
123 | where reference has been optimized out. | |
124 | ||
125 | - non-unit-at-a-time | |
126 | ||
127 | All functions are variables are output as early as possible to conserve | |
128 | memory consumption. This may or may not result in less memory used but | |
129 | it is still needed for some legacy code that rely on particular ordering | |
130 | of things output from the compiler. | |
131 | ||
132 | Varpool data structures are not used and variables are output directly. | |
133 | ||
134 | Functions are output early using call of | |
135 | cgraph_assemble_pending_function from cgraph_finalize_function. The | |
136 | decision on whether function is needed is made more conservative so | |
137 | uninlininable static functions are needed too. During the call-graph | |
138 | construction the edge destinations are not marked as reachable and it | |
139 | is completely relied upn assemble_variable to mark them. | |
140 | ||
141 | Inlining decision heuristics | |
142 | ??? Move this to separate file after tree-ssa merge. | |
143 | ||
144 | We separate inlining decisions from the inliner itself and store it | |
b01d837f | 145 | inside callgraph as so called inline plan. Refer to cgraph.c |
18c6ada9 JH |
146 | documentation about particular representation of inline plans in the |
147 | callgraph | |
148 | ||
149 | The implementation of particular heuristics is separated from | |
150 | the rest of code to make it easier to replace it with more complicated | |
151 | implementation in the future. The rest of inlining code acts as a | |
152 | library aimed to modify the callgraph and verify that the parameters | |
153 | on code size growth fits. | |
154 | ||
155 | To mark given call inline, use cgraph_mark_inline function, the | |
156 | verification is performed by cgraph_default_inline_p and | |
157 | cgraph_check_inline_limits. | |
158 | ||
159 | The heuristics implements simple knapsack style algorithm ordering | |
160 | all functions by their "profitability" (estimated by code size growth) | |
161 | and inlining them in priority order. | |
162 | ||
163 | cgraph_decide_inlining implements heuristics taking whole callgraph | |
164 | into account, while cgraph_decide_inlining_incrementally considers | |
165 | only one function at a time and is used in non-unit-at-a-time mode. */ | |
9b3e897d | 166 | |
6674a6ce | 167 | |
1c4a429a JH |
168 | #include "config.h" |
169 | #include "system.h" | |
170 | #include "coretypes.h" | |
171 | #include "tm.h" | |
172 | #include "tree.h" | |
c9b9aa64 | 173 | #include "rtl.h" |
6674a6ce | 174 | #include "tree-flow.h" |
1c4a429a JH |
175 | #include "tree-inline.h" |
176 | #include "langhooks.h" | |
0c58f841 | 177 | #include "pointer-set.h" |
1c4a429a JH |
178 | #include "toplev.h" |
179 | #include "flags.h" | |
180 | #include "ggc.h" | |
181 | #include "debug.h" | |
182 | #include "target.h" | |
183 | #include "cgraph.h" | |
dafc5b82 | 184 | #include "diagnostic.h" |
a194aa56 | 185 | #include "timevar.h" |
b58b1157 JH |
186 | #include "params.h" |
187 | #include "fibheap.h" | |
188 | #include "c-common.h" | |
dc0bfe6a | 189 | #include "intl.h" |
902edd36 | 190 | #include "function.h" |
6674a6ce | 191 | #include "tree-gimple.h" |
b4861090 | 192 | #include "tree-pass.h" |
cd9c7bd2 | 193 | #include "output.h" |
b58b1157 | 194 | |
a20af5b8 | 195 | static void cgraph_expand_all_functions (void); |
db0e878d AJ |
196 | static void cgraph_mark_functions_to_output (void); |
197 | static void cgraph_expand_function (struct cgraph_node *); | |
198 | static tree record_call_1 (tree *, int *, void *); | |
85c33455 | 199 | static void cgraph_mark_local_functions (void); |
4a46cbfb | 200 | static void cgraph_analyze_function (struct cgraph_node *node); |
b58b1157 | 201 | |
7dff32e6 JS |
202 | /* Records tree nodes seen in cgraph_create_edges. Simply using |
203 | walk_tree_without_duplicates doesn't guarantee each node is visited | |
204 | once because it gets a new htab upon each recursive call from | |
205 | record_calls_1. */ | |
0c58f841 | 206 | static struct pointer_set_t *visited_nodes; |
7dff32e6 | 207 | |
9b3e897d PB |
208 | static FILE *cgraph_dump_file; |
209 | ||
8dafba3c RH |
210 | /* Determine if function DECL is needed. That is, visible to something |
211 | either outside this translation unit, something magic in the system | |
212 | configury, or (if not doing unit-at-a-time) to something we havn't | |
213 | seen yet. */ | |
214 | ||
215 | static bool | |
216 | decide_is_function_needed (struct cgraph_node *node, tree decl) | |
217 | { | |
8f235343 | 218 | tree origin; |
6de9cd9a | 219 | |
8dafba3c RH |
220 | /* If we decided it was needed before, but at the time we didn't have |
221 | the body of the function available, then it's still needed. We have | |
222 | to go back and re-check its dependencies now. */ | |
223 | if (node->needed) | |
224 | return true; | |
225 | ||
226 | /* Externally visible functions must be output. The exception is | |
227 | COMDAT functions that must be output only when they are needed. */ | |
228 | if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) | |
229 | return true; | |
230 | ||
231 | /* Constructors and destructors are reachable from the runtime by | |
232 | some mechanism. */ | |
233 | if (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl)) | |
234 | return true; | |
235 | ||
236 | /* If the user told us it is used, then it must be so. */ | |
237 | if (lookup_attribute ("used", DECL_ATTRIBUTES (decl))) | |
238 | return true; | |
239 | ||
240 | /* ??? If the assembler name is set by hand, it is possible to assemble | |
241 | the name later after finalizing the function and the fact is noticed | |
242 | in assemble_name then. This is arguably a bug. */ | |
243 | if (DECL_ASSEMBLER_NAME_SET_P (decl) | |
244 | && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) | |
245 | return true; | |
246 | ||
247 | if (flag_unit_at_a_time) | |
248 | return false; | |
249 | ||
250 | /* If not doing unit at a time, then we'll only defer this function | |
251 | if its marked for inlining. Otherwise we want to emit it now. */ | |
252 | ||
253 | /* "extern inline" functions are never output locally. */ | |
254 | if (DECL_EXTERNAL (decl)) | |
255 | return false; | |
6de9cd9a DN |
256 | /* Nested functions of extern inline function shall not be emit unless |
257 | we inlined the origin. */ | |
8f235343 JH |
258 | for (origin = decl_function_context (decl); origin; |
259 | origin = decl_function_context (origin)) | |
260 | if (DECL_EXTERNAL (origin)) | |
6de9cd9a | 261 | return false; |
2067c116 | 262 | /* We want to emit COMDAT functions only when absolutely necessary. */ |
d853a20e | 263 | if (DECL_COMDAT (decl)) |
8dafba3c RH |
264 | return false; |
265 | if (!DECL_INLINE (decl) | |
266 | || (!node->local.disregard_inline_limits | |
267 | /* When declared inline, defer even the uninlinable functions. | |
7d82fe7c | 268 | This allows them to be eliminated when unused. */ |
8dafba3c | 269 | && !DECL_DECLARED_INLINE_P (decl) |
d4d1ebc1 | 270 | && (!node->local.inlinable || !cgraph_default_inline_p (node)))) |
8dafba3c RH |
271 | return true; |
272 | ||
273 | return false; | |
274 | } | |
275 | ||
aabcd309 KH |
276 | /* Walk the decls we marked as necessary and see if they reference new |
277 | variables or functions and add them into the worklists. */ | |
cd9c7bd2 JH |
278 | static bool |
279 | cgraph_varpool_analyze_pending_decls (void) | |
280 | { | |
281 | bool changed = false; | |
282 | timevar_push (TV_CGRAPH); | |
283 | ||
284 | while (cgraph_varpool_first_unanalyzed_node) | |
285 | { | |
286 | tree decl = cgraph_varpool_first_unanalyzed_node->decl; | |
287 | ||
288 | cgraph_varpool_first_unanalyzed_node->analyzed = true; | |
289 | ||
290 | cgraph_varpool_first_unanalyzed_node = cgraph_varpool_first_unanalyzed_node->next_needed; | |
291 | ||
292 | if (DECL_INITIAL (decl)) | |
293 | cgraph_create_edges (NULL, DECL_INITIAL (decl)); | |
294 | changed = true; | |
295 | } | |
296 | timevar_pop (TV_CGRAPH); | |
297 | return changed; | |
298 | } | |
299 | ||
300 | /* Optimization of function bodies might've rendered some variables as | |
aabcd309 | 301 | unnecessary so we want to avoid these from being compiled. |
cd9c7bd2 JH |
302 | |
303 | This is done by prunning the queue and keeping only the variables that | |
aabcd309 | 304 | really appear needed (ie they are either externally visible or referenced |
cd9c7bd2 JH |
305 | by compiled function). Re-doing the reachability analysis on variables |
306 | brings back the remaining variables referenced by these. */ | |
307 | static void | |
308 | cgraph_varpool_remove_unreferenced_decls (void) | |
309 | { | |
310 | struct cgraph_varpool_node *next, *node = cgraph_varpool_nodes_queue; | |
311 | ||
312 | cgraph_varpool_reset_queue (); | |
313 | ||
314 | if (errorcount || sorrycount) | |
315 | return; | |
316 | ||
317 | while (node) | |
318 | { | |
319 | tree decl = node->decl; | |
320 | next = node->next_needed; | |
321 | node->needed = 0; | |
322 | ||
323 | if (node->finalized | |
324 | && ((DECL_ASSEMBLER_NAME_SET_P (decl) | |
325 | && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) | |
326 | || node->force_output | |
327 | || decide_is_variable_needed (node, decl))) | |
328 | cgraph_varpool_mark_needed_node (node); | |
329 | ||
330 | node = next; | |
331 | } | |
332 | cgraph_varpool_analyze_pending_decls (); | |
333 | } | |
6674a6ce | 334 | |
6674a6ce | 335 | |
d853a20e JH |
336 | /* When not doing unit-at-a-time, output all functions enqueued. |
337 | Return true when such a functions were found. */ | |
f6d1b84a RH |
338 | |
339 | bool | |
d853a20e JH |
340 | cgraph_assemble_pending_functions (void) |
341 | { | |
342 | bool output = false; | |
343 | ||
344 | if (flag_unit_at_a_time) | |
345 | return false; | |
346 | ||
347 | while (cgraph_nodes_queue) | |
348 | { | |
349 | struct cgraph_node *n = cgraph_nodes_queue; | |
350 | ||
351 | cgraph_nodes_queue = cgraph_nodes_queue->next_needed; | |
18c6ada9 | 352 | n->next_needed = NULL; |
12527dce RH |
353 | if (!n->global.inlined_to |
354 | && !n->alias | |
355 | && !DECL_EXTERNAL (n->decl)) | |
f6d1b84a RH |
356 | { |
357 | cgraph_expand_function (n); | |
358 | output = true; | |
359 | } | |
d853a20e | 360 | } |
f6d1b84a | 361 | |
d853a20e JH |
362 | return output; |
363 | } | |
364 | ||
6b00c969 RH |
365 | /* DECL has been parsed. Take it, queue it, compile it at the whim of the |
366 | logic in effect. If NESTED is true, then our caller cannot stand to have | |
367 | the garbage collector run at the moment. We would need to either create | |
368 | a new GC context, or just not compile right now. */ | |
1c4a429a JH |
369 | |
370 | void | |
6b00c969 | 371 | cgraph_finalize_function (tree decl, bool nested) |
1c4a429a JH |
372 | { |
373 | struct cgraph_node *node = cgraph_node (decl); | |
374 | ||
d853a20e JH |
375 | if (node->local.finalized) |
376 | { | |
377 | /* As an GCC extension we allow redefinition of the function. The | |
6b00c969 RH |
378 | semantics when both copies of bodies differ is not well defined. |
379 | We replace the old body with new body so in unit at a time mode | |
380 | we always use new body, while in normal mode we may end up with | |
381 | old body inlined into some functions and new body expanded and | |
382 | inlined in others. | |
d853a20e | 383 | |
6b00c969 | 384 | ??? It may make more sense to use one body for inlining and other |
2067c116 | 385 | body for expanding the function but this is difficult to do. */ |
6b00c969 | 386 | |
f6d1b84a RH |
387 | /* If node->output is set, then this is a unit-at-a-time compilation |
388 | and we have already begun whole-unit analysis. This is *not* | |
389 | testing for whether we've already emitted the function. That | |
390 | case can be sort-of legitimately seen with real function | |
391 | redefinition errors. I would argue that the front end should | |
392 | never present us with such a case, but don't enforce that for now. */ | |
341c100f | 393 | gcc_assert (!node->output); |
6b00c969 | 394 | |
1ae58c30 | 395 | /* Reset our data structures so we can analyze the function again. */ |
cd4dea62 JH |
396 | memset (&node->local, 0, sizeof (node->local)); |
397 | memset (&node->global, 0, sizeof (node->global)); | |
398 | memset (&node->rtl, 0, sizeof (node->rtl)); | |
25c84396 | 399 | node->analyzed = false; |
95c755e9 | 400 | node->local.redefined_extern_inline = true; |
58203599 JJ |
401 | |
402 | if (!flag_unit_at_a_time) | |
403 | { | |
404 | struct cgraph_node *n; | |
405 | ||
406 | for (n = cgraph_nodes; n; n = n->next) | |
407 | if (n->global.inlined_to == node) | |
408 | cgraph_remove_node (n); | |
409 | } | |
410 | ||
2563c224 | 411 | cgraph_node_remove_callees (node); |
6b00c969 | 412 | |
cd4dea62 JH |
413 | /* We may need to re-queue the node for assembling in case |
414 | we already proceeded it and ignored as not needed. */ | |
415 | if (node->reachable && !flag_unit_at_a_time) | |
d853a20e | 416 | { |
cd4dea62 JH |
417 | struct cgraph_node *n; |
418 | ||
419 | for (n = cgraph_nodes_queue; n; n = n->next_needed) | |
420 | if (n == node) | |
421 | break; | |
422 | if (!n) | |
423 | node->reachable = 0; | |
d853a20e | 424 | } |
d853a20e | 425 | } |
6b00c969 | 426 | |
d853a20e | 427 | notice_global_symbol (decl); |
1c4a429a | 428 | node->decl = decl; |
f6981e16 | 429 | node->local.finalized = true; |
8f235343 JH |
430 | if (node->nested) |
431 | lower_nested_functions (decl); | |
432 | gcc_assert (!node->nested); | |
1c4a429a | 433 | |
8dafba3c RH |
434 | /* If not unit at a time, then we need to create the call graph |
435 | now, so that called functions can be queued and emitted now. */ | |
4a46cbfb | 436 | if (!flag_unit_at_a_time) |
d4d1ebc1 JH |
437 | { |
438 | cgraph_analyze_function (node); | |
439 | cgraph_decide_inlining_incrementally (node); | |
440 | } | |
4a46cbfb | 441 | |
8dafba3c RH |
442 | if (decide_is_function_needed (node, decl)) |
443 | cgraph_mark_needed_node (node); | |
444 | ||
6b00c969 RH |
445 | /* If not unit at a time, go ahead and emit everything we've found |
446 | to be reachable at this time. */ | |
447 | if (!nested) | |
d34cb6a1 JH |
448 | { |
449 | if (!cgraph_assemble_pending_functions ()) | |
450 | ggc_collect (); | |
451 | } | |
1668aabc | 452 | |
8dafba3c | 453 | /* If we've not yet emitted decl, tell the debug info about it. */ |
6b00c969 | 454 | if (!TREE_ASM_WRITTEN (decl)) |
8dafba3c | 455 | (*debug_hooks->deferred_inline_function) (decl); |
d173e685 | 456 | |
902edd36 JH |
457 | /* Possibly warn about unused parameters. */ |
458 | if (warn_unused_parameter) | |
459 | do_warn_unused_parameter (decl); | |
1c4a429a JH |
460 | } |
461 | ||
1c4a429a JH |
462 | /* Walk tree and record all calls. Called via walk_tree. */ |
463 | static tree | |
db0e878d | 464 | record_call_1 (tree *tp, int *walk_subtrees, void *data) |
1c4a429a | 465 | { |
25c84396 RH |
466 | tree t = *tp; |
467 | ||
468 | switch (TREE_CODE (t)) | |
1c4a429a | 469 | { |
25c84396 RH |
470 | case VAR_DECL: |
471 | /* ??? Really, we should mark this decl as *potentially* referenced | |
472 | by this function and re-examine whether the decl is actually used | |
473 | after rtl has been generated. */ | |
cd9c7bd2 | 474 | if (TREE_STATIC (t) || DECL_EXTERNAL (t)) |
4684cd27 MM |
475 | { |
476 | cgraph_varpool_mark_needed_node (cgraph_varpool_node (t)); | |
477 | if (lang_hooks.callgraph.analyze_expr) | |
478 | return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees, | |
479 | data); | |
480 | } | |
25c84396 RH |
481 | break; |
482 | ||
c7bcbc2c | 483 | case FDESC_EXPR: |
25c84396 RH |
484 | case ADDR_EXPR: |
485 | if (flag_unit_at_a_time) | |
486 | { | |
487 | /* Record dereferences to the functions. This makes the | |
488 | functions reachable unconditionally. */ | |
489 | tree decl = TREE_OPERAND (*tp, 0); | |
490 | if (TREE_CODE (decl) == FUNCTION_DECL) | |
491 | cgraph_mark_needed_node (cgraph_node (decl)); | |
492 | } | |
493 | break; | |
494 | ||
495 | case CALL_EXPR: | |
496 | { | |
497 | tree decl = get_callee_fndecl (*tp); | |
498 | if (decl && TREE_CODE (decl) == FUNCTION_DECL) | |
499 | { | |
18c6ada9 | 500 | cgraph_create_edge (data, cgraph_node (decl), *tp); |
25c84396 RH |
501 | |
502 | /* When we see a function call, we don't want to look at the | |
503 | function reference in the ADDR_EXPR that is hanging from | |
504 | the CALL_EXPR we're examining here, because we would | |
505 | conclude incorrectly that the function's address could be | |
506 | taken by something that is not a function call. So only | |
507 | walk the function parameter list, skip the other subtrees. */ | |
508 | ||
509 | walk_tree (&TREE_OPERAND (*tp, 1), record_call_1, data, | |
510 | visited_nodes); | |
511 | *walk_subtrees = 0; | |
512 | } | |
513 | break; | |
514 | } | |
515 | ||
516 | default: | |
517 | /* Save some cycles by not walking types and declaration as we | |
518 | won't find anything useful there anyway. */ | |
6615c446 | 519 | if (IS_TYPE_OR_DECL_P (*tp)) |
1c4a429a | 520 | { |
1c4a429a | 521 | *walk_subtrees = 0; |
25c84396 | 522 | break; |
1c4a429a | 523 | } |
25c84396 RH |
524 | |
525 | if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE) | |
ae2bcd98 | 526 | return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees, data); |
25c84396 | 527 | break; |
1c4a429a | 528 | } |
25c84396 | 529 | |
1c4a429a JH |
530 | return NULL; |
531 | } | |
532 | ||
18c6ada9 | 533 | /* Create cgraph edges for function calls inside BODY from NODE. */ |
1c4a429a JH |
534 | |
535 | void | |
18c6ada9 | 536 | cgraph_create_edges (struct cgraph_node *node, tree body) |
1c4a429a | 537 | { |
7660e67e SB |
538 | /* The nodes we're interested in are never shared, so walk |
539 | the tree ignoring duplicates. */ | |
0c58f841 | 540 | visited_nodes = pointer_set_create (); |
18c6ada9 | 541 | walk_tree (&body, record_call_1, node, visited_nodes); |
0c58f841 | 542 | pointer_set_destroy (visited_nodes); |
7dff32e6 | 543 | visited_nodes = NULL; |
1c4a429a JH |
544 | } |
545 | ||
18c6ada9 JH |
546 | static bool error_found; |
547 | ||
e1990f69 BE |
548 | /* Callback of verify_cgraph_node. Check that all call_exprs have |
549 | cgraph nodes. */ | |
7120d046 | 550 | |
18c6ada9 JH |
551 | static tree |
552 | verify_cgraph_node_1 (tree *tp, int *walk_subtrees, void *data) | |
553 | { | |
554 | tree t = *tp; | |
555 | tree decl; | |
556 | ||
557 | if (TREE_CODE (t) == CALL_EXPR && (decl = get_callee_fndecl (t))) | |
558 | { | |
559 | struct cgraph_edge *e = cgraph_edge (data, t); | |
560 | if (e) | |
561 | { | |
562 | if (e->aux) | |
563 | { | |
564 | error ("Shared call_expr:"); | |
565 | debug_tree (t); | |
566 | error_found = true; | |
567 | } | |
568 | if (e->callee->decl != cgraph_node (decl)->decl) | |
569 | { | |
570 | error ("Edge points to wrong declaration:"); | |
571 | debug_tree (e->callee->decl); | |
572 | fprintf (stderr," Instead of:"); | |
573 | debug_tree (decl); | |
574 | } | |
575 | e->aux = (void *)1; | |
576 | } | |
577 | else | |
578 | { | |
579 | error ("Missing callgraph edge for call expr:"); | |
580 | debug_tree (t); | |
581 | error_found = true; | |
582 | } | |
583 | } | |
7120d046 | 584 | |
18c6ada9 JH |
585 | /* Save some cycles by not walking types and declaration as we |
586 | won't find anything useful there anyway. */ | |
6615c446 | 587 | if (IS_TYPE_OR_DECL_P (*tp)) |
7120d046 RK |
588 | *walk_subtrees = 0; |
589 | ||
18c6ada9 JH |
590 | return NULL_TREE; |
591 | } | |
592 | ||
593 | /* Verify cgraph nodes of given cgraph node. */ | |
594 | void | |
595 | verify_cgraph_node (struct cgraph_node *node) | |
596 | { | |
597 | struct cgraph_edge *e; | |
598 | struct cgraph_node *main_clone; | |
599 | ||
600 | timevar_push (TV_CGRAPH_VERIFY); | |
601 | error_found = false; | |
602 | for (e = node->callees; e; e = e->next_callee) | |
603 | if (e->aux) | |
604 | { | |
605 | error ("Aux field set for edge %s->%s", | |
606 | cgraph_node_name (e->caller), cgraph_node_name (e->callee)); | |
607 | error_found = true; | |
608 | } | |
609 | for (e = node->callers; e; e = e->next_caller) | |
610 | { | |
611 | if (!e->inline_failed) | |
612 | { | |
613 | if (node->global.inlined_to | |
614 | != (e->caller->global.inlined_to | |
615 | ? e->caller->global.inlined_to : e->caller)) | |
616 | { | |
617 | error ("Inlined_to pointer is wrong"); | |
618 | error_found = true; | |
619 | } | |
620 | if (node->callers->next_caller) | |
621 | { | |
622 | error ("Multiple inline callers"); | |
623 | error_found = true; | |
624 | } | |
625 | } | |
626 | else | |
627 | if (node->global.inlined_to) | |
628 | { | |
629 | error ("Inlined_to pointer set for noninline callers"); | |
630 | error_found = true; | |
631 | } | |
632 | } | |
633 | if (!node->callers && node->global.inlined_to) | |
634 | { | |
635 | error ("Inlined_to pointer is set but no predecesors found"); | |
636 | error_found = true; | |
637 | } | |
638 | if (node->global.inlined_to == node) | |
639 | { | |
640 | error ("Inlined_to pointer reffers to itself"); | |
641 | error_found = true; | |
642 | } | |
643 | ||
644 | for (main_clone = cgraph_node (node->decl); main_clone; | |
645 | main_clone = main_clone->next_clone) | |
646 | if (main_clone == node) | |
647 | break; | |
648 | if (!node) | |
649 | { | |
650 | error ("Node not found in DECL_ASSEMBLER_NAME hash"); | |
651 | error_found = true; | |
652 | } | |
653 | ||
654 | if (node->analyzed | |
655 | && DECL_SAVED_TREE (node->decl) && !TREE_ASM_WRITTEN (node->decl) | |
656 | && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to)) | |
657 | { | |
658 | walk_tree_without_duplicates (&DECL_SAVED_TREE (node->decl), | |
659 | verify_cgraph_node_1, node); | |
660 | for (e = node->callees; e; e = e->next_callee) | |
661 | { | |
662 | if (!e->aux) | |
663 | { | |
664 | error ("Edge %s->%s has no corresponding call_expr", | |
665 | cgraph_node_name (e->caller), | |
666 | cgraph_node_name (e->callee)); | |
667 | error_found = true; | |
668 | } | |
669 | e->aux = 0; | |
670 | } | |
671 | } | |
672 | if (error_found) | |
673 | { | |
674 | dump_cgraph_node (stderr, node); | |
675 | internal_error ("verify_cgraph_node failed."); | |
676 | } | |
677 | timevar_pop (TV_CGRAPH_VERIFY); | |
678 | } | |
679 | ||
680 | /* Verify whole cgraph structure. */ | |
681 | void | |
682 | verify_cgraph (void) | |
683 | { | |
684 | struct cgraph_node *node; | |
685 | ||
89480522 JH |
686 | if (sorrycount || errorcount) |
687 | return; | |
688 | ||
18c6ada9 JH |
689 | for (node = cgraph_nodes; node; node = node->next) |
690 | verify_cgraph_node (node); | |
691 | } | |
692 | ||
cd9c7bd2 JH |
693 | |
694 | /* Output all variables enqueued to be assembled. */ | |
695 | bool | |
696 | cgraph_varpool_assemble_pending_decls (void) | |
697 | { | |
698 | bool changed = false; | |
699 | ||
700 | if (errorcount || sorrycount) | |
701 | return false; | |
702 | ||
703 | /* EH might mark decls as needed during expansion. This should be safe since | |
704 | we don't create references to new function, but it should not be used | |
705 | elsewhere. */ | |
706 | cgraph_varpool_analyze_pending_decls (); | |
707 | ||
708 | while (cgraph_varpool_nodes_queue) | |
709 | { | |
710 | tree decl = cgraph_varpool_nodes_queue->decl; | |
711 | struct cgraph_varpool_node *node = cgraph_varpool_nodes_queue; | |
712 | ||
713 | cgraph_varpool_nodes_queue = cgraph_varpool_nodes_queue->next_needed; | |
714 | if (!TREE_ASM_WRITTEN (decl) && !node->alias && !DECL_EXTERNAL (decl)) | |
715 | { | |
716 | assemble_variable (decl, 0, 1, 0); | |
717 | changed = true; | |
718 | } | |
719 | node->next_needed = NULL; | |
720 | } | |
721 | return changed; | |
722 | } | |
723 | ||
e767b5be JH |
724 | /* Analyze the function scheduled to be output. */ |
725 | static void | |
726 | cgraph_analyze_function (struct cgraph_node *node) | |
727 | { | |
728 | tree decl = node->decl; | |
dc0bfe6a | 729 | struct cgraph_edge *e; |
e767b5be | 730 | |
25c84396 | 731 | current_function_decl = decl; |
e767b5be JH |
732 | |
733 | /* First kill forward declaration so reverse inlining works properly. */ | |
18c6ada9 | 734 | cgraph_create_edges (node, DECL_SAVED_TREE (decl)); |
e767b5be JH |
735 | |
736 | node->local.inlinable = tree_inlinable_function_p (decl); | |
6de9cd9a | 737 | node->local.self_insns = estimate_num_insns (DECL_SAVED_TREE (decl)); |
e767b5be JH |
738 | if (node->local.inlinable) |
739 | node->local.disregard_inline_limits | |
ae2bcd98 | 740 | = lang_hooks.tree_inlining.disregard_inline_limits (decl); |
dc0bfe6a | 741 | for (e = node->callers; e; e = e->next_caller) |
18c6ada9 JH |
742 | { |
743 | if (node->local.redefined_extern_inline) | |
744 | e->inline_failed = N_("redefined extern inline functions are not " | |
745 | "considered for inlining"); | |
746 | else if (!node->local.inlinable) | |
747 | e->inline_failed = N_("function not inlinable"); | |
748 | else | |
749 | e->inline_failed = N_("function not considered for inlining"); | |
750 | } | |
b684a3df JH |
751 | if (flag_really_no_inline && !node->local.disregard_inline_limits) |
752 | node->local.inlinable = 0; | |
e767b5be JH |
753 | /* Inlining characteristics are maintained by the cgraph_mark_inline. */ |
754 | node->global.insns = node->local.self_insns; | |
e767b5be | 755 | |
25c84396 | 756 | node->analyzed = true; |
d853a20e | 757 | current_function_decl = NULL; |
e767b5be JH |
758 | } |
759 | ||
1c4a429a JH |
760 | /* Analyze the whole compilation unit once it is parsed completely. */ |
761 | ||
762 | void | |
db0e878d | 763 | cgraph_finalize_compilation_unit (void) |
1c4a429a JH |
764 | { |
765 | struct cgraph_node *node; | |
cd9c7bd2 | 766 | /* Keep track of already processed nodes when called multiple times for |
aabcd309 | 767 | intermodule optimization. */ |
cd9c7bd2 | 768 | static struct cgraph_node *first_analyzed; |
1c4a429a | 769 | |
e4d5432a RH |
770 | finish_aliases_1 (); |
771 | ||
4a46cbfb | 772 | if (!flag_unit_at_a_time) |
d853a20e JH |
773 | { |
774 | cgraph_assemble_pending_functions (); | |
775 | return; | |
776 | } | |
4a46cbfb | 777 | |
b58b1157 | 778 | if (!quiet_flag) |
cd9c7bd2 JH |
779 | { |
780 | fprintf (stderr, "\nAnalyzing compilation unit"); | |
781 | fflush (stderr); | |
782 | } | |
e69529cd | 783 | |
a194aa56 | 784 | timevar_push (TV_CGRAPH); |
cd9c7bd2 | 785 | cgraph_varpool_analyze_pending_decls (); |
a194aa56 | 786 | if (cgraph_dump_file) |
1c4a429a | 787 | { |
7d82fe7c | 788 | fprintf (cgraph_dump_file, "Initial entry points:"); |
cd9c7bd2 | 789 | for (node = cgraph_nodes; node != first_analyzed; node = node->next) |
1668aabc | 790 | if (node->needed && DECL_SAVED_TREE (node->decl)) |
a194aa56 JH |
791 | fprintf (cgraph_dump_file, " %s", cgraph_node_name (node)); |
792 | fprintf (cgraph_dump_file, "\n"); | |
1c4a429a JH |
793 | } |
794 | ||
7660e67e SB |
795 | /* Propagate reachability flag and lower representation of all reachable |
796 | functions. In the future, lowering will introduce new functions and | |
797 | new entry points on the way (by template instantiation and virtual | |
798 | method table generation for instance). */ | |
1668aabc | 799 | while (cgraph_nodes_queue) |
1c4a429a | 800 | { |
e767b5be | 801 | struct cgraph_edge *edge; |
1668aabc JH |
802 | tree decl = cgraph_nodes_queue->decl; |
803 | ||
804 | node = cgraph_nodes_queue; | |
8bd87c4e | 805 | cgraph_nodes_queue = cgraph_nodes_queue->next_needed; |
18c6ada9 | 806 | node->next_needed = NULL; |
1c4a429a | 807 | |
cd4dea62 | 808 | /* ??? It is possible to create extern inline function and later using |
9d203871 | 809 | weak alias attribute to kill its body. See |
cd4dea62 JH |
810 | gcc.c-torture/compile/20011119-1.c */ |
811 | if (!DECL_SAVED_TREE (decl)) | |
812 | continue; | |
813 | ||
341c100f NS |
814 | gcc_assert (!node->analyzed && node->reachable); |
815 | gcc_assert (DECL_SAVED_TREE (decl)); | |
1c4a429a | 816 | |
e767b5be | 817 | cgraph_analyze_function (node); |
8dafba3c | 818 | |
1c4a429a | 819 | for (edge = node->callees; edge; edge = edge->next_callee) |
e767b5be | 820 | if (!edge->callee->reachable) |
8dafba3c RH |
821 | cgraph_mark_reachable_node (edge->callee); |
822 | ||
cd9c7bd2 | 823 | cgraph_varpool_analyze_pending_decls (); |
1c4a429a | 824 | } |
8dafba3c | 825 | |
1668aabc JH |
826 | /* Collect entry points to the unit. */ |
827 | ||
a194aa56 | 828 | if (cgraph_dump_file) |
1668aabc | 829 | { |
7d82fe7c | 830 | fprintf (cgraph_dump_file, "Unit entry points:"); |
cd9c7bd2 | 831 | for (node = cgraph_nodes; node != first_analyzed; node = node->next) |
1668aabc | 832 | if (node->needed && DECL_SAVED_TREE (node->decl)) |
a194aa56 | 833 | fprintf (cgraph_dump_file, " %s", cgraph_node_name (node)); |
7d82fe7c | 834 | fprintf (cgraph_dump_file, "\n\nInitial "); |
e767b5be | 835 | dump_cgraph (cgraph_dump_file); |
1668aabc | 836 | } |
7660e67e | 837 | |
a194aa56 JH |
838 | if (cgraph_dump_file) |
839 | fprintf (cgraph_dump_file, "\nReclaiming functions:"); | |
1c4a429a | 840 | |
cd9c7bd2 | 841 | for (node = cgraph_nodes; node != first_analyzed; node = node->next) |
1c4a429a JH |
842 | { |
843 | tree decl = node->decl; | |
844 | ||
845 | if (!node->reachable && DECL_SAVED_TREE (decl)) | |
846 | { | |
a194aa56 JH |
847 | if (cgraph_dump_file) |
848 | fprintf (cgraph_dump_file, " %s", cgraph_node_name (node)); | |
18c6ada9 | 849 | cgraph_remove_node (node); |
1c4a429a | 850 | } |
9b0436b7 JH |
851 | else |
852 | node->next_needed = NULL; | |
1c4a429a | 853 | } |
a194aa56 | 854 | if (cgraph_dump_file) |
7d82fe7c KC |
855 | { |
856 | fprintf (cgraph_dump_file, "\n\nReclaimed "); | |
857 | dump_cgraph (cgraph_dump_file); | |
858 | } | |
cd9c7bd2 | 859 | first_analyzed = cgraph_nodes; |
1c4a429a | 860 | ggc_collect (); |
a194aa56 | 861 | timevar_pop (TV_CGRAPH); |
1c4a429a | 862 | } |
1c4a429a JH |
863 | /* Figure out what functions we want to assemble. */ |
864 | ||
865 | static void | |
db0e878d | 866 | cgraph_mark_functions_to_output (void) |
1c4a429a JH |
867 | { |
868 | struct cgraph_node *node; | |
869 | ||
1c4a429a JH |
870 | for (node = cgraph_nodes; node; node = node->next) |
871 | { | |
872 | tree decl = node->decl; | |
b58b1157 | 873 | struct cgraph_edge *e; |
341c100f NS |
874 | |
875 | gcc_assert (!node->output); | |
b58b1157 JH |
876 | |
877 | for (e = node->callers; e; e = e->next_caller) | |
dc0bfe6a | 878 | if (e->inline_failed) |
b58b1157 | 879 | break; |
1c4a429a | 880 | |
7660e67e SB |
881 | /* We need to output all local functions that are used and not |
882 | always inlined, as well as those that are reachable from | |
883 | outside the current compilation unit. */ | |
1c4a429a | 884 | if (DECL_SAVED_TREE (decl) |
18c6ada9 | 885 | && !node->global.inlined_to |
1c4a429a | 886 | && (node->needed |
b58b1157 | 887 | || (e && node->reachable)) |
6de9cd9a | 888 | && !TREE_ASM_WRITTEN (decl) |
1c4a429a JH |
889 | && !DECL_EXTERNAL (decl)) |
890 | node->output = 1; | |
341c100f | 891 | else |
1a2caa7a NS |
892 | { |
893 | /* We should've reclaimed all functions that are not needed. */ | |
894 | #ifdef ENABLE_CHECKING | |
895 | if (!node->global.inlined_to && DECL_SAVED_TREE (decl) | |
896 | && !DECL_EXTERNAL (decl)) | |
897 | { | |
898 | dump_cgraph_node (stderr, node); | |
899 | internal_error ("failed to reclaim unneeded function"); | |
900 | } | |
901 | #endif | |
902 | gcc_assert (node->global.inlined_to || !DECL_SAVED_TREE (decl) | |
903 | || DECL_EXTERNAL (decl)); | |
904 | ||
905 | } | |
906 | ||
18d13f34 JH |
907 | } |
908 | } | |
909 | ||
1c4a429a | 910 | /* Expand function specified by NODE. */ |
7660e67e | 911 | |
1c4a429a | 912 | static void |
db0e878d | 913 | cgraph_expand_function (struct cgraph_node *node) |
1c4a429a JH |
914 | { |
915 | tree decl = node->decl; | |
916 | ||
18c6ada9 | 917 | /* We ought to not compile any inline clones. */ |
341c100f | 918 | gcc_assert (!node->global.inlined_to); |
18c6ada9 | 919 | |
6b00c969 RH |
920 | if (flag_unit_at_a_time) |
921 | announce_function (decl); | |
18d13f34 | 922 | |
a3546141 | 923 | /* Generate RTL for the body of DECL. */ |
ae2bcd98 | 924 | lang_hooks.callgraph.expand_function (decl); |
18d13f34 | 925 | |
6de9cd9a DN |
926 | /* Make sure that BE didn't give up on compiling. */ |
927 | /* ??? Can happen with nested function of extern inline. */ | |
341c100f | 928 | gcc_assert (TREE_ASM_WRITTEN (node->decl)); |
18c6ada9 | 929 | |
1c4a429a | 930 | current_function_decl = NULL; |
89480522 | 931 | if (!cgraph_preserve_function_body_p (node->decl)) |
6de9cd9a DN |
932 | { |
933 | DECL_SAVED_TREE (node->decl) = NULL; | |
934 | DECL_STRUCT_FUNCTION (node->decl) = NULL; | |
6de9cd9a | 935 | DECL_INITIAL (node->decl) = error_mark_node; |
229031d0 | 936 | /* Eliminate all call edges. This is important so the call_expr no longer |
89480522 | 937 | points to the dead function body. */ |
2563c224 | 938 | cgraph_node_remove_callees (node); |
6de9cd9a | 939 | } |
1c4a429a JH |
940 | } |
941 | ||
18c6ada9 | 942 | /* Return true when CALLER_DECL should be inlined into CALLEE_DECL. */ |
b58b1157 JH |
943 | |
944 | bool | |
18c6ada9 | 945 | cgraph_inline_p (struct cgraph_edge *e, const char **reason) |
b58b1157 | 946 | { |
18c6ada9 JH |
947 | *reason = e->inline_failed; |
948 | return !e->inline_failed; | |
b58b1157 | 949 | } |
18c6ada9 | 950 | |
6674a6ce | 951 | |
6674a6ce | 952 | |
db0e878d AJ |
953 | /* Expand all functions that must be output. |
954 | ||
b58b1157 JH |
955 | Attempt to topologically sort the nodes so function is output when |
956 | all called functions are already assembled to allow data to be | |
a98ebe2e | 957 | propagated across the callgraph. Use a stack to get smaller distance |
d1a6adeb | 958 | between a function and its callees (later we may choose to use a more |
b58b1157 JH |
959 | sophisticated algorithm for function reordering; we will likely want |
960 | to use subsections to make the output functions appear in top-down | |
961 | order). */ | |
962 | ||
963 | static void | |
a20af5b8 | 964 | cgraph_expand_all_functions (void) |
b58b1157 JH |
965 | { |
966 | struct cgraph_node *node; | |
967 | struct cgraph_node **order = | |
b3c3af2f | 968 | xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *)); |
18c6ada9 | 969 | int order_pos = 0, new_order_pos = 0; |
b58b1157 JH |
970 | int i; |
971 | ||
b58b1157 | 972 | order_pos = cgraph_postorder (order); |
341c100f | 973 | gcc_assert (order_pos == cgraph_n_nodes); |
b58b1157 | 974 | |
1ae58c30 | 975 | /* Garbage collector may remove inline clones we eliminate during |
18c6ada9 JH |
976 | optimization. So we must be sure to not reference them. */ |
977 | for (i = 0; i < order_pos; i++) | |
978 | if (order[i]->output) | |
979 | order[new_order_pos++] = order[i]; | |
980 | ||
981 | for (i = new_order_pos - 1; i >= 0; i--) | |
b58b1157 JH |
982 | { |
983 | node = order[i]; | |
984 | if (node->output) | |
985 | { | |
341c100f | 986 | gcc_assert (node->reachable); |
b58b1157 JH |
987 | node->output = 0; |
988 | cgraph_expand_function (node); | |
989 | } | |
990 | } | |
991 | free (order); | |
992 | } | |
993 | ||
85c33455 | 994 | /* Mark all local functions. |
6674a6ce KZ |
995 | |
996 | A local function is one whose calls can occur only in the current | |
997 | compilation unit and all its calls are explicit, so we can change | |
998 | its calling convention. We simply mark all static functions whose | |
85c33455 | 999 | address is not taken as local. */ |
b58b1157 JH |
1000 | |
1001 | static void | |
85c33455 | 1002 | cgraph_mark_local_functions (void) |
b58b1157 JH |
1003 | { |
1004 | struct cgraph_node *node; | |
1005 | ||
b58b1157 JH |
1006 | /* Figure out functions we want to assemble. */ |
1007 | for (node = cgraph_nodes; node; node = node->next) | |
1008 | { | |
1009 | node->local.local = (!node->needed | |
1010 | && DECL_SAVED_TREE (node->decl) | |
1011 | && !TREE_PUBLIC (node->decl)); | |
b58b1157 | 1012 | } |
6674a6ce | 1013 | |
b58b1157 | 1014 | if (cgraph_dump_file) |
6674a6ce KZ |
1015 | { |
1016 | fprintf (cgraph_dump_file, "\nMarking local functions:"); | |
1017 | for (node = cgraph_nodes; node; node = node->next) | |
1018 | if (node->local.local) | |
1019 | fprintf (cgraph_dump_file, " %s", cgraph_node_name (node)); | |
1020 | fprintf (cgraph_dump_file, "\n\n"); | |
85c33455 | 1021 | } |
6674a6ce | 1022 | } |
dafc5b82 | 1023 | |
18c6ada9 JH |
1024 | /* Return true when function body of DECL still needs to be kept around |
1025 | for later re-use. */ | |
1026 | bool | |
1027 | cgraph_preserve_function_body_p (tree decl) | |
1028 | { | |
1029 | struct cgraph_node *node; | |
1030 | /* Keep the body; we're going to dump it. */ | |
9f8628ba | 1031 | if (dump_enabled_p (TDI_tree_all)) |
18c6ada9 JH |
1032 | return true; |
1033 | if (!cgraph_global_info_ready) | |
1034 | return (DECL_INLINE (decl) && !flag_really_no_inline); | |
1035 | /* Look if there is any clone around. */ | |
1036 | for (node = cgraph_node (decl); node; node = node->next_clone) | |
1037 | if (node->global.inlined_to) | |
1038 | return true; | |
1039 | return false; | |
1040 | } | |
1041 | ||
1c4a429a JH |
1042 | /* Perform simple optimizations based on callgraph. */ |
1043 | ||
1044 | void | |
db0e878d | 1045 | cgraph_optimize (void) |
1c4a429a | 1046 | { |
18c6ada9 JH |
1047 | #ifdef ENABLE_CHECKING |
1048 | verify_cgraph (); | |
1049 | #endif | |
4a46cbfb | 1050 | if (!flag_unit_at_a_time) |
cd9c7bd2 JH |
1051 | { |
1052 | cgraph_varpool_assemble_pending_decls (); | |
1053 | return; | |
1054 | } | |
857e7259 ZW |
1055 | |
1056 | process_pending_assemble_externals (); | |
cd9c7bd2 JH |
1057 | |
1058 | /* Frontend may output common variables after the unit has been finalized. | |
1059 | It is safe to deal with them here as they are always zero initialized. */ | |
1060 | cgraph_varpool_analyze_pending_decls (); | |
857e7259 | 1061 | |
a194aa56 | 1062 | timevar_push (TV_CGRAPHOPT); |
b58b1157 JH |
1063 | if (!quiet_flag) |
1064 | fprintf (stderr, "Performing intraprocedural optimizations\n"); | |
7d82fe7c | 1065 | |
85c33455 | 1066 | cgraph_mark_local_functions (); |
a194aa56 JH |
1067 | if (cgraph_dump_file) |
1068 | { | |
7d82fe7c | 1069 | fprintf (cgraph_dump_file, "Marked "); |
a194aa56 JH |
1070 | dump_cgraph (cgraph_dump_file); |
1071 | } | |
b4861090 | 1072 | ipa_passes (); |
dafc5b82 | 1073 | cgraph_global_info_ready = true; |
a194aa56 JH |
1074 | if (cgraph_dump_file) |
1075 | { | |
7d82fe7c | 1076 | fprintf (cgraph_dump_file, "Optimized "); |
a194aa56 | 1077 | dump_cgraph (cgraph_dump_file); |
cd9c7bd2 | 1078 | dump_varpool (cgraph_dump_file); |
a194aa56 JH |
1079 | } |
1080 | timevar_pop (TV_CGRAPHOPT); | |
1c4a429a | 1081 | |
b58b1157 | 1082 | /* Output everything. */ |
7d82fe7c KC |
1083 | if (!quiet_flag) |
1084 | fprintf (stderr, "Assembling functions:\n"); | |
18c6ada9 JH |
1085 | #ifdef ENABLE_CHECKING |
1086 | verify_cgraph (); | |
1087 | #endif | |
6674a6ce | 1088 | |
6674a6ce | 1089 | cgraph_mark_functions_to_output (); |
a20af5b8 | 1090 | cgraph_expand_all_functions (); |
cd9c7bd2 JH |
1091 | cgraph_varpool_remove_unreferenced_decls (); |
1092 | ||
1093 | cgraph_varpool_assemble_pending_decls (); | |
1094 | ||
a194aa56 JH |
1095 | if (cgraph_dump_file) |
1096 | { | |
7d82fe7c | 1097 | fprintf (cgraph_dump_file, "\nFinal "); |
a194aa56 JH |
1098 | dump_cgraph (cgraph_dump_file); |
1099 | } | |
18c6ada9 JH |
1100 | #ifdef ENABLE_CHECKING |
1101 | verify_cgraph (); | |
6de9cd9a DN |
1102 | /* Double check that all inline clones are gone and that all |
1103 | function bodies have been released from memory. */ | |
1104 | if (flag_unit_at_a_time | |
9f8628ba | 1105 | && !dump_enabled_p (TDI_tree_all) |
6de9cd9a DN |
1106 | && !(sorrycount || errorcount)) |
1107 | { | |
1108 | struct cgraph_node *node; | |
1109 | bool error_found = false; | |
1110 | ||
1111 | for (node = cgraph_nodes; node; node = node->next) | |
1112 | if (node->analyzed | |
1113 | && (node->global.inlined_to | |
1114 | || DECL_SAVED_TREE (node->decl))) | |
1115 | { | |
1116 | error_found = true; | |
1117 | dump_cgraph_node (stderr, node); | |
1118 | } | |
1119 | if (error_found) | |
1120 | internal_error ("Nodes with no released memory found."); | |
1121 | } | |
18c6ada9 | 1122 | #endif |
1c4a429a | 1123 | } |
c9b9aa64 RH |
1124 | |
1125 | /* Generate and emit a static constructor or destructor. WHICH must be | |
1126 | one of 'I' or 'D'. BODY should be a STATEMENT_LIST containing | |
1127 | GENERIC statements. */ | |
1128 | ||
1129 | void | |
35b6fdcf | 1130 | cgraph_build_static_cdtor (char which, tree body, int priority) |
c9b9aa64 RH |
1131 | { |
1132 | static int counter = 0; | |
1133 | char which_buf[16]; | |
b785f485 | 1134 | tree decl, name, resdecl; |
c9b9aa64 RH |
1135 | |
1136 | sprintf (which_buf, "%c_%d", which, counter++); | |
1137 | name = get_file_function_name_long (which_buf); | |
1138 | ||
1139 | decl = build_decl (FUNCTION_DECL, name, | |
1140 | build_function_type (void_type_node, void_list_node)); | |
1141 | current_function_decl = decl; | |
1142 | ||
b785f485 RH |
1143 | resdecl = build_decl (RESULT_DECL, NULL_TREE, void_type_node); |
1144 | DECL_ARTIFICIAL (resdecl) = 1; | |
1145 | DECL_IGNORED_P (resdecl) = 1; | |
1146 | DECL_RESULT (decl) = resdecl; | |
1147 | ||
c9b9aa64 RH |
1148 | allocate_struct_function (decl); |
1149 | ||
1150 | TREE_STATIC (decl) = 1; | |
1151 | TREE_USED (decl) = 1; | |
1152 | DECL_ARTIFICIAL (decl) = 1; | |
1153 | DECL_IGNORED_P (decl) = 1; | |
1154 | DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; | |
1155 | DECL_SAVED_TREE (decl) = body; | |
1156 | TREE_PUBLIC (decl) = ! targetm.have_ctors_dtors; | |
1157 | DECL_UNINLINABLE (decl) = 1; | |
1158 | ||
1159 | DECL_INITIAL (decl) = make_node (BLOCK); | |
1160 | TREE_USED (DECL_INITIAL (decl)) = 1; | |
1161 | ||
1162 | DECL_SOURCE_LOCATION (decl) = input_location; | |
1163 | cfun->function_end_locus = input_location; | |
1164 | ||
341c100f NS |
1165 | switch (which) |
1166 | { | |
1167 | case 'I': | |
1168 | DECL_STATIC_CONSTRUCTOR (decl) = 1; | |
1169 | break; | |
1170 | case 'D': | |
1171 | DECL_STATIC_DESTRUCTOR (decl) = 1; | |
1172 | break; | |
1173 | default: | |
1174 | gcc_unreachable (); | |
1175 | } | |
c9b9aa64 RH |
1176 | |
1177 | gimplify_function_tree (decl); | |
1178 | ||
1179 | /* ??? We will get called LATE in the compilation process. */ | |
1180 | if (cgraph_global_info_ready) | |
0f0377f6 | 1181 | tree_rest_of_compilation (decl); |
c9b9aa64 RH |
1182 | else |
1183 | cgraph_finalize_function (decl, 0); | |
1184 | ||
1185 | if (targetm.have_ctors_dtors) | |
1186 | { | |
1187 | void (*fn) (rtx, int); | |
1188 | ||
1189 | if (which == 'I') | |
1190 | fn = targetm.asm_out.constructor; | |
1191 | else | |
1192 | fn = targetm.asm_out.destructor; | |
35b6fdcf | 1193 | fn (XEXP (DECL_RTL (decl), 0), priority); |
c9b9aa64 RH |
1194 | } |
1195 | } | |
9b3e897d PB |
1196 | |
1197 | void | |
1198 | init_cgraph (void) | |
1199 | { | |
1200 | cgraph_dump_file = dump_begin (TDI_cgraph, NULL); | |
1201 | } |