]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ipa.c
* graph.c (init_graph_slim_pretty_print): Remove.
[thirdparty/gcc.git] / gcc / ipa.c
CommitLineData
65c1a668 1/* Basic IPA optimizations and utilities.
711789cc 2 Copyright (C) 2003-2013 Free Software Foundation, Inc.
65c1a668 3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8c4c00c1 8Software Foundation; either version 3, or (at your option) any later
65c1a668 9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
8c4c00c1 17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
65c1a668 19
20#include "config.h"
21#include "system.h"
22#include "coretypes.h"
23#include "tm.h"
24#include "cgraph.h"
f37a5008 25#include "tree-pass.h"
ccf4ab6b 26#include "gimple.h"
13f90d63 27#include "ggc.h"
8dfbf71d 28#include "flags.h"
ced14259 29#include "pointer-set.h"
a53e7471 30#include "target.h"
31#include "tree-iterator.h"
7771d558 32#include "ipa-utils.h"
da751785 33#include "pointer-set.h"
91f0ab48 34#include "ipa-inline.h"
9e179a64 35#include "hash-table.h"
36#include "tree-inline.h"
37#include "profile.h"
38#include "params.h"
39#include "lto-streamer.h"
40#include "data-streamer.h"
65c1a668 41
15ca8f90 42/* Return true when NODE can not be local. Worker for cgraph_local_node_p. */
43
44static bool
45cgraph_non_local_node_p_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
46{
47 /* FIXME: Aliases can be local, but i386 gets thunks wrong then. */
48 return !(cgraph_only_called_directly_or_aliased_p (node)
49 && !ipa_ref_has_aliases_p (&node->symbol.ref_list)
50 && node->symbol.definition
51 && !DECL_EXTERNAL (node->symbol.decl)
52 && !node->symbol.externally_visible
53 && !node->symbol.used_from_other_partition
54 && !node->symbol.in_other_partition);
55}
56
57/* Return true when function can be marked local. */
58
59static bool
60cgraph_local_node_p (struct cgraph_node *node)
61{
62 struct cgraph_node *n = cgraph_function_or_thunk_node (node, NULL);
63
64 /* FIXME: thunks can be considered local, but we need prevent i386
65 from attempting to change calling convention of them. */
66 if (n->thunk.thunk_p)
67 return false;
68 return !cgraph_for_node_and_aliases (n,
69 cgraph_non_local_node_p_1, NULL, true);
70
71}
72
73/* Return true when NODE has ADDR reference. */
74
75static bool
76has_addr_references_p (struct cgraph_node *node,
77 void *data ATTRIBUTE_UNUSED)
78{
79 int i;
80 struct ipa_ref *ref;
81
82 for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list,
83 i, ref); i++)
84 if (ref->use == IPA_REF_ADDR)
85 return true;
86 return false;
87}
88
21f41380 89/* Look for all functions inlined to NODE and update their inlined_to pointers
90 to INLINED_TO. */
91
92static void
93update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to)
94{
95 struct cgraph_edge *e;
96 for (e = node->callees; e; e = e->next_callee)
97 if (e->callee->global.inlined_to)
98 {
99 e->callee->global.inlined_to = inlined_to;
100 update_inlined_to_pointer (e->callee, inlined_to);
101 }
102}
103
91f0ab48 104/* Add symtab NODE to queue starting at FIRST.
9da87cb8 105
106 The queue is linked via AUX pointers and terminated by pointer to 1.
107 We enqueue nodes at two occasions: when we find them reachable or when we find
108 their bodies needed for further clonning. In the second case we mark them
109 by pointer to 2 after processing so they are re-queue when they become
110 reachable. */
6f932b06 111
112static void
91f0ab48 113enqueue_node (symtab_node node, symtab_node *first,
114 struct pointer_set_t *reachable)
6f932b06 115{
9da87cb8 116 /* Node is still in queue; do nothing. */
7d0d0ce1 117 if (node->symbol.aux && node->symbol.aux != (void *) 2)
9da87cb8 118 return;
119 /* Node was already processed as unreachable, re-enqueue
120 only if it became reachable now. */
da751785 121 if (node->symbol.aux == (void *)2 && !pointer_set_contains (reachable, node))
9da87cb8 122 return;
7d0d0ce1 123 node->symbol.aux = *first;
6f932b06 124 *first = node;
125}
126
6f932b06 127/* Process references. */
128
129static void
130process_references (struct ipa_ref_list *list,
91f0ab48 131 symtab_node *first,
da751785 132 bool before_inlining_p,
133 struct pointer_set_t *reachable)
6f932b06 134{
135 int i;
136 struct ipa_ref *ref;
137 for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
138 {
15ca8f90 139 symtab_node node = ref->referred;
140
b9b49047 141 if (node->symbol.definition && !node->symbol.in_other_partition
48669653 142 && ((!DECL_EXTERNAL (node->symbol.decl) || node->symbol.alias)
15ca8f90 143 || (before_inlining_p
144 /* We use variable constructors during late complation for
145 constant folding. Keep references alive so partitioning
146 knows about potential references. */
147 || (TREE_CODE (node->symbol.decl) == VAR_DECL
df8d3e89 148 && flag_wpa
149 && ctor_for_folding (node->symbol.decl)
150 != error_mark_node))))
15ca8f90 151 pointer_set_insert (reachable, node);
152 enqueue_node ((symtab_node) node, first, reachable);
6f932b06 153 }
154}
155
36a32361 156
65c1a668 157/* Perform reachability analysis and reclaim all unreachable nodes.
91f0ab48 158
159 The algorithm is basically mark&sweep but with some extra refinements:
160
161 - reachable extern inline functions needs special handling; the bodies needs
162 to stay in memory until inlining in hope that they will be inlined.
163 After inlining we release their bodies and turn them into unanalyzed
164 nodes even when they are reachable.
165
166 BEFORE_INLINING_P specify whether we are before or after inlining.
167
168 - virtual functions are kept in callgraph even if they seem unreachable in
169 hope calls to them will be devirtualized.
170
171 Again we remove them after inlining. In late optimization some
172 devirtualization may happen, but it is not importnat since we won't inline
173 the call. In theory early opts and IPA should work out all important cases.
174
175 - virtual clones needs bodies of their origins for later materialization;
176 this means that we want to keep the body even if the origin is unreachable
177 otherwise. To avoid origin from sitting in the callgraph and being
178 walked by IPA passes, we turn them into unanalyzed nodes with body
179 defined.
180
181 We maintain set of function declaration where body needs to stay in
182 body_needed_for_clonning
183
184 Inline clones represent special case: their declaration match the
185 declaration of origin and cgraph_remove_node already knows how to
186 reshape callgraph and preserve body when offline copy of function or
187 inline clone is being removed.
188
aa419a52 189 - C++ virtual tables keyed to other unit are represented as DECL_EXTERNAL
190 variables with DECL_INITIAL set. We finalize these and keep reachable
191 ones around for constant folding purposes. After inlining we however
192 stop walking their references to let everything static referneced by them
193 to be removed when it is otherwise unreachable.
194
91f0ab48 195 We maintain queue of both reachable symbols (i.e. defined symbols that needs
196 to stay) and symbols that are in boundary (i.e. external symbols referenced
197 by reachable symbols or origins of clones). The queue is represented
198 as linked list by AUX pointer terminated by 1.
199
200 A the end we keep all reachable symbols. For symbols in boundary we always
201 turn definition into a declaration, but we may keep function body around
202 based on body_needed_for_clonning
203
204 All symbols that enter the queue have AUX pointer non-zero and are in the
205 boundary. Pointer set REACHABLE is used to track reachable symbols.
206
207 Every symbol can be visited twice - once as part of boundary and once
208 as real reachable symbol. enqueue_node needs to decide whether the
209 node needs to be re-queued for second processing. For this purpose
210 we set AUX pointer of processed symbols in the boundary to constant 2. */
65c1a668 211
212bool
91f0ab48 213symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
65c1a668 214{
91f0ab48 215 symtab_node first = (symtab_node) (void *) 1;
f4ec5ce1 216 struct cgraph_node *node, *next;
6f932b06 217 struct varpool_node *vnode, *vnext;
65c1a668 218 bool changed = false;
da751785 219 struct pointer_set_t *reachable = pointer_set_create ();
91f0ab48 220 struct pointer_set_t *body_needed_for_clonning = pointer_set_create ();
65c1a668 221
222#ifdef ENABLE_CHECKING
3e7775f6 223 verify_symtab ();
65c1a668 224#endif
3f5be5f4 225 if (file)
226 fprintf (file, "\nReclaiming functions:");
65c1a668 227#ifdef ENABLE_CHECKING
7c455d87 228 FOR_EACH_FUNCTION (node)
7d0d0ce1 229 gcc_assert (!node->symbol.aux);
7c455d87 230 FOR_EACH_VARIABLE (vnode)
7d0d0ce1 231 gcc_assert (!vnode->symbol.aux);
65c1a668 232#endif
7f74ac6b 233 /* Mark functions whose bodies are obviously needed.
234 This is mostly when they can be referenced externally. Inline clones
235 are special since their declarations are shared with master clone and thus
236 cgraph_can_remove_if_no_direct_calls_and_refs_p should not be called on them. */
abb1a237 237 FOR_EACH_FUNCTION (node)
238 {
239 node->used_as_abstract_origin = false;
240 if (node->symbol.definition
241 && !node->global.inlined_to
f08369a7 242 && !node->symbol.in_other_partition
abb1a237 243 && (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node)
244 /* Keep around virtual functions for possible devirtualization. */
245 || (before_inlining_p
246 && DECL_VIRTUAL_P (node->symbol.decl))))
247 {
248 gcc_assert (!node->global.inlined_to);
249 pointer_set_insert (reachable, node);
250 enqueue_node ((symtab_node)node, &first, reachable);
251 }
252 else
253 gcc_assert (!node->symbol.aux);
254 }
7f74ac6b 255
256 /* Mark variables that are obviously needed. */
91f0ab48 257 FOR_EACH_DEFINED_VARIABLE (vnode)
b9b49047 258 if (!varpool_can_remove_if_no_refs (vnode)
259 && !vnode->symbol.in_other_partition)
91f0ab48 260 {
261 pointer_set_insert (reachable, vnode);
262 enqueue_node ((symtab_node)vnode, &first, reachable);
263 }
264
265 /* Perform reachability analysis. */
266 while (first != (symtab_node) (void *) 1)
6f932b06 267 {
91f0ab48 268 bool in_boundary_p = !pointer_set_contains (reachable, first);
269 symtab_node node = first;
65c1a668 270
91f0ab48 271 first = (symtab_node)first->symbol.aux;
9da87cb8 272
91f0ab48 273 /* If we are processing symbol in boundary, mark its AUX pointer for
274 possible later re-processing in enqueue_node. */
275 if (in_boundary_p)
276 node->symbol.aux = (void *)2;
277 else
278 {
abb1a237 279 if (DECL_ABSTRACT_ORIGIN (node->symbol.decl))
280 {
281 struct cgraph_node *origin_node
282 = cgraph_get_create_real_symbol_node (DECL_ABSTRACT_ORIGIN (node->symbol.decl));
283 origin_node->used_as_abstract_origin = true;
284 enqueue_node ((symtab_node) origin_node, &first, reachable);
285 }
91f0ab48 286 /* If any symbol in a comdat group is reachable, force
287 all other in the same comdat group to be also reachable. */
288 if (node->symbol.same_comdat_group)
289 {
290 symtab_node next;
291 for (next = node->symbol.same_comdat_group;
292 next != node;
293 next = next->symbol.same_comdat_group)
294 if (!pointer_set_insert (reachable, next))
295 enqueue_node ((symtab_node) next, &first, reachable);
296 }
297 /* Mark references as reachable. */
298 process_references (&node->symbol.ref_list, &first,
299 before_inlining_p, reachable);
300 }
9da87cb8 301
2dc9831f 302 if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
6f932b06 303 {
91f0ab48 304 /* Mark the callees reachable unless they are direct calls to extern
305 inline functions we decided to not inline. */
306 if (!in_boundary_p)
e12f85b7 307 {
91f0ab48 308 struct cgraph_edge *e;
309 for (e = cnode->callees; e; e = e->next_callee)
71ca01ff 310 {
15ca8f90 311 if (e->callee->symbol.definition
b9b49047 312 && !e->callee->symbol.in_other_partition
71ca01ff 313 && (!e->inline_failed
7d0d0ce1 314 || !DECL_EXTERNAL (e->callee->symbol.decl)
48669653 315 || e->callee->symbol.alias
71ca01ff 316 || before_inlining_p))
da751785 317 pointer_set_insert (reachable, e->callee);
91f0ab48 318 enqueue_node ((symtab_node) e->callee, &first, reachable);
da751785 319 }
91f0ab48 320
321 /* When inline clone exists, mark body to be preserved so when removing
322 offline copy of the function we don't kill it. */
b9b49047 323 if (cnode->global.inlined_to)
91f0ab48 324 pointer_set_insert (body_needed_for_clonning, cnode->symbol.decl);
61c2c7b1 325
b9b49047 326 /* For non-inline clones, force their origins to the boundary and ensure
327 that body is not removed. */
328 while (cnode->clone_of)
329 {
330 bool noninline = cnode->clone_of->symbol.decl != cnode->symbol.decl;
331 cnode = cnode->clone_of;
332 if (noninline)
333 {
334 pointer_set_insert (body_needed_for_clonning, cnode->symbol.decl);
335 enqueue_node ((symtab_node)cnode, &first, reachable);
336 }
6f932b06 337 }
ee3f5fc0 338 }
6f932b06 339 }
aa419a52 340 /* When we see constructor of external variable, keep referred nodes in the
2dc9831f 341 boundary. This will also hold initializers of the external vars NODE
342 refers to. */
343 varpool_node *vnode = dyn_cast <varpool_node> (node);
344 if (vnode
aa419a52 345 && DECL_EXTERNAL (node->symbol.decl)
15ca8f90 346 && !vnode->symbol.alias
aa419a52 347 && in_boundary_p)
2dc9831f 348 {
aa419a52 349 struct ipa_ref *ref;
2dc9831f 350 for (int i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref); i++)
aa419a52 351 enqueue_node (ref->referred, &first, reachable);
2dc9831f 352 }
65c1a668 353 }
354
91f0ab48 355 /* Remove unreachable functions. */
0704fb2e 356 for (node = cgraph_first_function (); node; node = next)
65c1a668 357 {
0704fb2e 358 next = cgraph_next_function (node);
15ca8f90 359
360 /* If node is not needed at all, remove it. */
7d0d0ce1 361 if (!node->symbol.aux)
65c1a668 362 {
3f5be5f4 363 if (file)
364 fprintf (file, " %s", cgraph_node_name (node));
91f0ab48 365 cgraph_remove_node (node);
366 changed = true;
367 }
15ca8f90 368 /* If node is unreachable, remove its body. */
91f0ab48 369 else if (!pointer_set_contains (reachable, node))
370 {
15ca8f90 371 if (!pointer_set_contains (body_needed_for_clonning, node->symbol.decl))
372 cgraph_release_function_body (node);
b9b49047 373 else if (!node->clone_of)
4df870fd 374 gcc_assert (in_lto_p || DECL_RESULT (node->symbol.decl));
15ca8f90 375 if (node->symbol.definition)
7fb046a4 376 {
91f0ab48 377 if (file)
378 fprintf (file, " %s", cgraph_node_name (node));
15ca8f90 379 cgraph_reset_node (node);
7fb046a4 380 changed = true;
381 }
65c1a668 382 }
b9b49047 383 else
384 gcc_assert (node->clone_of || !cgraph_function_with_gimple_body_p (node)
4df870fd 385 || in_lto_p || DECL_RESULT (node->symbol.decl));
65c1a668 386 }
91f0ab48 387
388 /* Inline clones might be kept around so their materializing allows further
389 cloning. If the function the clone is inlined into is removed, we need
390 to turn it into normal cone. */
7c455d87 391 FOR_EACH_FUNCTION (node)
ccf4ab6b 392 {
ccf4ab6b 393 if (node->global.inlined_to
394 && !node->callers)
395 {
396 gcc_assert (node->clones);
21f41380 397 node->global.inlined_to = NULL;
398 update_inlined_to_pointer (node, node);
ccf4ab6b 399 }
7d0d0ce1 400 node->symbol.aux = NULL;
ccf4ab6b 401 }
8dfbf71d 402
91f0ab48 403 /* Remove unreachable variables. */
8dfbf71d 404 if (file)
91f0ab48 405 fprintf (file, "\nReclaiming variables:");
0704fb2e 406 for (vnode = varpool_first_variable (); vnode; vnode = vnext)
6f932b06 407 {
0704fb2e 408 vnext = varpool_next_variable (vnode);
f1a7feee 409 if (!vnode->symbol.aux
410 /* For can_refer_decl_in_current_unit_p we want to track for
411 all external variables if they are defined in other partition
412 or not. */
413 && (!flag_ltrans || !DECL_EXTERNAL (vnode->symbol.decl)))
91f0ab48 414 {
8dfbf71d 415 if (file)
416 fprintf (file, " %s", varpool_node_name (vnode));
417 varpool_remove_node (vnode);
418 changed = true;
6f932b06 419 }
91f0ab48 420 else if (!pointer_set_contains (reachable, vnode))
421 {
df8d3e89 422 tree init;
15ca8f90 423 if (vnode->symbol.definition)
91f0ab48 424 {
425 if (file)
426 fprintf (file, " %s", varpool_node_name (vnode));
427 changed = true;
428 }
15ca8f90 429 vnode->symbol.definition = false;
430 vnode->symbol.analyzed = false;
91f0ab48 431 vnode->symbol.aux = NULL;
15ca8f90 432
433 /* Keep body if it may be useful for constant folding. */
df8d3e89 434 if ((init = ctor_for_folding (vnode->symbol.decl)) == error_mark_node)
15ca8f90 435 varpool_remove_initializer (vnode);
df8d3e89 436 else
437 DECL_INITIAL (vnode->symbol.decl) = init;
15ca8f90 438 ipa_remove_all_references (&vnode->symbol.ref_list);
91f0ab48 439 }
440 else
441 vnode->symbol.aux = NULL;
6f932b06 442 }
8dfbf71d 443
91f0ab48 444 pointer_set_destroy (reachable);
445 pointer_set_destroy (body_needed_for_clonning);
8dfbf71d 446
91f0ab48 447 /* Now update address_taken flags and try to promote functions to be local. */
cdedc740 448 if (file)
449 fprintf (file, "\nClearing address taken flags:");
7c455d87 450 FOR_EACH_DEFINED_FUNCTION (node)
7d0d0ce1 451 if (node->symbol.address_taken
452 && !node->symbol.used_from_other_partition)
cdedc740 453 {
36a32361 454 if (!cgraph_for_node_and_aliases (node, has_addr_references_p, NULL, true))
cdedc740 455 {
456 if (file)
457 fprintf (file, " %s", cgraph_node_name (node));
7d0d0ce1 458 node->symbol.address_taken = false;
8dfbf71d 459 changed = true;
460 if (cgraph_local_node_p (node))
461 {
462 node->local.local = true;
463 if (file)
464 fprintf (file, " (local)");
465 }
cdedc740 466 }
467 }
c7b2cc59 468 if (file)
469 fprintf (file, "\n");
6f932b06 470
09a2e412 471#ifdef ENABLE_CHECKING
3e7775f6 472 verify_symtab ();
09a2e412 473#endif
34e5cced 474
f8bfd7f7 475 /* If we removed something, perhaps profile could be improved. */
f1f41a6c 476 if (changed && optimize && inline_edge_summary_vec.exists ())
f8bfd7f7 477 FOR_EACH_DEFINED_FUNCTION (node)
478 cgraph_propagate_frequency (node);
479
65c1a668 480 return changed;
481}
f37a5008 482
8dfbf71d 483/* Discover variables that have no longer address taken or that are read only
484 and update their flags.
485
486 FIXME: This can not be done in between gimplify and omp_expand since
487 readonly flag plays role on what is shared and what is not. Currently we do
023a28e1 488 this transformation as part of whole program visibility and re-do at
489 ipa-reference pass (to take into account clonning), but it would
490 make sense to do it before early optimizations. */
8dfbf71d 491
492void
493ipa_discover_readonly_nonaddressable_vars (void)
494{
495 struct varpool_node *vnode;
496 if (dump_file)
497 fprintf (dump_file, "Clearing variable flags:");
7c455d87 498 FOR_EACH_VARIABLE (vnode)
15ca8f90 499 if (vnode->symbol.definition && varpool_all_refs_explicit_p (vnode)
7d0d0ce1 500 && (TREE_ADDRESSABLE (vnode->symbol.decl)
501 || !TREE_READONLY (vnode->symbol.decl)))
8dfbf71d 502 {
503 bool written = false;
504 bool address_taken = false;
505 int i;
506 struct ipa_ref *ref;
04ec15fa 507 for (i = 0; ipa_ref_list_referring_iterate (&vnode->symbol.ref_list,
7d0d0ce1 508 i, ref)
8dfbf71d 509 && (!written || !address_taken); i++)
510 switch (ref->use)
511 {
512 case IPA_REF_ADDR:
513 address_taken = true;
514 break;
515 case IPA_REF_LOAD:
516 break;
517 case IPA_REF_STORE:
518 written = true;
519 break;
520 }
7d0d0ce1 521 if (TREE_ADDRESSABLE (vnode->symbol.decl) && !address_taken)
8dfbf71d 522 {
523 if (dump_file)
524 fprintf (dump_file, " %s (addressable)", varpool_node_name (vnode));
7d0d0ce1 525 TREE_ADDRESSABLE (vnode->symbol.decl) = 0;
8dfbf71d 526 }
7d0d0ce1 527 if (!TREE_READONLY (vnode->symbol.decl) && !address_taken && !written
8dfbf71d 528 /* Making variable in explicit section readonly can cause section
529 type conflict.
530 See e.g. gcc.c-torture/compile/pr23237.c */
7d0d0ce1 531 && DECL_SECTION_NAME (vnode->symbol.decl) == NULL)
8dfbf71d 532 {
533 if (dump_file)
534 fprintf (dump_file, " %s (read-only)", varpool_node_name (vnode));
7d0d0ce1 535 TREE_READONLY (vnode->symbol.decl) = 1;
8dfbf71d 536 }
537 }
538 if (dump_file)
539 fprintf (dump_file, "\n");
540}
541
6e673e69 542/* Return true when there is a reference to node and it is not vtable. */
543static bool
6a1c0403 544address_taken_from_non_vtable_p (symtab_node node)
6e673e69 545{
546 int i;
547 struct ipa_ref *ref;
04ec15fa 548 for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list,
7d0d0ce1 549 i, ref); i++)
9ff0849c 550 if (ref->use == IPA_REF_ADDR)
551 {
552 struct varpool_node *node;
2dc9831f 553 if (is_a <cgraph_node> (ref->referring))
9ff0849c 554 return true;
04ec15fa 555 node = ipa_ref_referring_varpool_node (ref);
7d0d0ce1 556 if (!DECL_VIRTUAL_P (node->symbol.decl))
9ff0849c 557 return true;
558 }
6e673e69 559 return false;
560}
561
6a1c0403 562/* A helper for comdat_can_be_unshared_p. */
563
564static bool
565comdat_can_be_unshared_p_1 (symtab_node node)
566{
567 /* When address is taken, we don't know if equality comparison won't
ccb1572b 568 break eventually. Exception are virutal functions and vtables,
569 where this is not possible by language standard. */
6a1c0403 570 if (!DECL_VIRTUAL_P (node->symbol.decl)
571 && address_taken_from_non_vtable_p (node))
572 return false;
573
574 /* If the symbol is used in some weird way, better to not touch it. */
575 if (node->symbol.force_output)
576 return false;
577
578 /* Explicit instantiations needs to be output when possibly
579 used externally. */
580 if (node->symbol.forced_by_abi
581 && TREE_PUBLIC (node->symbol.decl)
582 && (node->symbol.resolution != LDPR_PREVAILING_DEF_IRONLY
583 && !flag_whole_program))
584 return false;
585
586 /* Non-readonly and volatile variables can not be duplicated. */
587 if (is_a <varpool_node> (node)
588 && (!TREE_READONLY (node->symbol.decl)
589 || TREE_THIS_VOLATILE (node->symbol.decl)))
590 return false;
591 return true;
592}
593
6e673e69 594/* COMDAT functions must be shared only if they have address taken,
595 otherwise we can produce our own private implementation with
596 -fwhole-program.
597 Return true when turning COMDAT functoin static can not lead to wrong
598 code when the resulting object links with a library defining same COMDAT.
599
600 Virtual functions do have their addresses taken from the vtables,
601 but in C++ there is no way to compare their addresses for equality. */
602
15ca8f90 603static bool
6a1c0403 604comdat_can_be_unshared_p (symtab_node node)
6e673e69 605{
6a1c0403 606 if (!comdat_can_be_unshared_p_1 (node))
6e673e69 607 return false;
7d0d0ce1 608 if (node->symbol.same_comdat_group)
6e673e69 609 {
6a1c0403 610 symtab_node next;
6e673e69 611
612 /* If more than one function is in the same COMDAT group, it must
613 be shared even if just one function in the comdat group has
614 address taken. */
6a1c0403 615 for (next = node->symbol.same_comdat_group;
616 next != node; next = next->symbol.same_comdat_group)
617 if (!comdat_can_be_unshared_p_1 (next))
618 return false;
6e673e69 619 }
620 return true;
621}
622
8dfbf71d 623/* Return true when function NODE should be considered externally visible. */
624
59dd4830 625static bool
c70f46b0 626cgraph_externally_visible_p (struct cgraph_node *node,
7dfe7ce5 627 bool whole_program)
59dd4830 628{
15ca8f90 629 if (!node->symbol.definition)
e51ee2f1 630 return false;
a1d135c3 631 if (!TREE_PUBLIC (node->symbol.decl)
632 || DECL_EXTERNAL (node->symbol.decl))
59dd4830 633 return false;
ced14259 634
62324487 635 /* Do not try to localize built-in functions yet. One of problems is that we
636 end up mangling their asm for WHOPR that makes it impossible to call them
637 using the implicit built-in declarations anymore. Similarly this enables
638 us to remove them as unreachable before actual calls may appear during
639 expansion or folding. */
7d0d0ce1 640 if (DECL_BUILT_IN (node->symbol.decl))
62324487 641 return true;
642
10325323 643 /* If linker counts on us, we must preserve the function. */
cf951b1a 644 if (symtab_used_from_object_file_p ((symtab_node) node))
10325323 645 return true;
7d0d0ce1 646 if (DECL_PRESERVE_P (node->symbol.decl))
d66ff47e 647 return true;
7d0d0ce1 648 if (lookup_attribute ("externally_visible",
649 DECL_ATTRIBUTES (node->symbol.decl)))
d66ff47e 650 return true;
62433d51 651 if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
7d0d0ce1 652 && lookup_attribute ("dllexport",
653 DECL_ATTRIBUTES (node->symbol.decl)))
62433d51 654 return true;
7d0d0ce1 655 if (node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY)
37ec4be4 656 return false;
6e673e69 657 /* When doing LTO or whole program, we can bring COMDAT functoins static.
658 This improves code quality and we know we will duplicate them at most twice
659 (in the case that we are not using plugin and link with object file
660 implementing same COMDAT) */
661 if ((in_lto_p || whole_program)
7d0d0ce1 662 && DECL_COMDAT (node->symbol.decl)
6a1c0403 663 && comdat_can_be_unshared_p ((symtab_node) node))
6e673e69 664 return false;
665
ced14259 666 /* When doing link time optimizations, hidden symbols become local. */
10325323 667 if (in_lto_p
7d0d0ce1 668 && (DECL_VISIBILITY (node->symbol.decl) == VISIBILITY_HIDDEN
669 || DECL_VISIBILITY (node->symbol.decl) == VISIBILITY_INTERNAL)
bfca27e3 670 /* Be sure that node is defined in IR file, not in other object
671 file. In that case we don't set used_from_other_object_file. */
15ca8f90 672 && node->symbol.definition)
ced14259 673 ;
674 else if (!whole_program)
b1be8e04 675 return true;
d66ff47e 676
7d0d0ce1 677 if (MAIN_NAME_P (DECL_NAME (node->symbol.decl)))
7fb046a4 678 return true;
d66ff47e 679
680 return false;
681}
682
683/* Return true when variable VNODE should be considered externally visible. */
684
124f4875 685bool
7dfe7ce5 686varpool_externally_visible_p (struct varpool_node *vnode)
d66ff47e 687{
aa419a52 688 if (DECL_EXTERNAL (vnode->symbol.decl))
689 return true;
690
a1d135c3 691 if (!TREE_PUBLIC (vnode->symbol.decl))
d66ff47e 692 return false;
693
d66ff47e 694 /* If linker counts on us, we must preserve the function. */
cf951b1a 695 if (symtab_used_from_object_file_p ((symtab_node) vnode))
d66ff47e 696 return true;
697
7d0d0ce1 698 if (DECL_HARD_REGISTER (vnode->symbol.decl))
54b1b91c 699 return true;
7d0d0ce1 700 if (DECL_PRESERVE_P (vnode->symbol.decl))
d66ff47e 701 return true;
702 if (lookup_attribute ("externally_visible",
7d0d0ce1 703 DECL_ATTRIBUTES (vnode->symbol.decl)))
d66ff47e 704 return true;
62433d51 705 if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
706 && lookup_attribute ("dllexport",
7d0d0ce1 707 DECL_ATTRIBUTES (vnode->symbol.decl)))
62433d51 708 return true;
d66ff47e 709
710 /* See if we have linker information about symbol not being used or
711 if we need to make guess based on the declaration.
712
713 Even if the linker clams the symbol is unused, never bring internal
714 symbols that are declared by user as used or externally visible.
715 This is needed for i.e. references from asm statements. */
cf951b1a 716 if (symtab_used_from_object_file_p ((symtab_node) vnode))
d66ff47e 717 return true;
7d0d0ce1 718 if (vnode->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY)
da722561 719 return false;
d66ff47e 720
9d75589a 721 /* As a special case, the COMDAT virtual tables can be unshared.
6e673e69 722 In LTO mode turn vtables into static variables. The variable is readonly,
723 so this does not enable more optimization, but referring static var
724 is faster for dynamic linking. Also this match logic hidding vtables
725 from LTO symbol tables. */
726 if ((in_lto_p || flag_whole_program)
6a1c0403 727 && DECL_COMDAT (vnode->symbol.decl)
728 && comdat_can_be_unshared_p ((symtab_node) vnode))
6e673e69 729 return false;
730
d66ff47e 731 /* When doing link time optimizations, hidden symbols become local. */
732 if (in_lto_p
7d0d0ce1 733 && (DECL_VISIBILITY (vnode->symbol.decl) == VISIBILITY_HIDDEN
734 || DECL_VISIBILITY (vnode->symbol.decl) == VISIBILITY_INTERNAL)
d66ff47e 735 /* Be sure that node is defined in IR file, not in other object
736 file. In that case we don't set used_from_other_object_file. */
15ca8f90 737 && vnode->symbol.definition)
d66ff47e 738 ;
739 else if (!flag_whole_program)
740 return true;
741
742 /* Do not attempt to privatize COMDATS by default.
743 This would break linking with C++ libraries sharing
744 inline definitions.
745
746 FIXME: We can do so for readonly vars with no address taken and
747 possibly also for vtables since no direct pointer comparsion is done.
748 It might be interesting to do so to reduce linking overhead. */
7d0d0ce1 749 if (DECL_COMDAT (vnode->symbol.decl) || DECL_WEAK (vnode->symbol.decl))
59dd4830 750 return true;
751 return false;
752}
753
44e82502 754/* Return true if reference to NODE can be replaced by a local alias.
755 Local aliases save dynamic linking overhead and enable more optimizations.
756 */
757
758bool
759can_replace_by_local_alias (symtab_node node)
760{
761 return (symtab_node_availability (node) > AVAIL_OVERWRITABLE
762 && !DECL_EXTERNAL (node->symbol.decl)
763 && (!DECL_ONE_ONLY (node->symbol.decl)
764 || node->symbol.resolution == LDPR_PREVAILING_DEF
765 || node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY
766 || node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY_EXP));
767}
768
f37a5008 769/* Mark visibility of all functions.
770
771 A local function is one whose calls can occur only in the current
772 compilation unit and all its calls are explicit, so we can change
773 its calling convention. We simply mark all static functions whose
774 address is not taken as local.
775
776 We also change the TREE_PUBLIC flag of all declarations that are public
777 in language point of view but we want to overwrite this default
778 via visibilities for the backend point of view. */
779
a757b4dc 780static unsigned int
59dd4830 781function_and_variable_visibility (bool whole_program)
f37a5008 782{
783 struct cgraph_node *node;
784 struct varpool_node *vnode;
ced14259 785
7dfe7ce5 786 /* All aliases should be procssed at this point. */
787 gcc_checking_assert (!alias_pairs || !alias_pairs->length());
f37a5008 788
7c455d87 789 FOR_EACH_FUNCTION (node)
f37a5008 790 {
7d0d0ce1 791 int flags = flags_from_decl_or_type (node->symbol.decl);
87ac7f21 792
793 /* Optimize away PURE and CONST constructors and destructors. */
7f74ac6b 794 if (optimize
795 && (flags & (ECF_CONST | ECF_PURE))
796 && !(flags & ECF_LOOPING_CONST_OR_PURE))
797 {
7d0d0ce1 798 DECL_STATIC_CONSTRUCTOR (node->symbol.decl) = 0;
799 DECL_STATIC_DESTRUCTOR (node->symbol.decl) = 0;
7f74ac6b 800 }
801
87ac7f21 802 /* Frontends and alias code marks nodes as needed before parsing is finished.
803 We may end up marking as node external nodes where this flag is meaningless
804 strip it. */
6a1c0403 805 if (DECL_EXTERNAL (node->symbol.decl) || !node->symbol.definition)
806 {
807 node->symbol.force_output = 0;
808 node->symbol.forced_by_abi = 0;
809 }
87ac7f21 810
59cb1238 811 /* C++ FE on lack of COMDAT support create local COMDAT functions
812 (that ought to be shared but can not due to object format
9d75589a 813 limitations). It is necessary to keep the flag to make rest of C++ FE
59cb1238 814 happy. Clear the flag here to avoid confusion in middle-end. */
7d0d0ce1 815 if (DECL_COMDAT (node->symbol.decl) && !TREE_PUBLIC (node->symbol.decl))
816 DECL_COMDAT (node->symbol.decl) = 0;
f2526cce 817
818 /* For external decls stop tracking same_comdat_group. It doesn't matter
819 what comdat group they are in when they won't be emitted in this TU. */
7d0d0ce1 820 if (node->symbol.same_comdat_group && DECL_EXTERNAL (node->symbol.decl))
0ca9d009 821 {
c524ac5d 822#ifdef ENABLE_CHECKING
7d0d0ce1 823 symtab_node n;
c524ac5d 824
7d0d0ce1 825 for (n = node->symbol.same_comdat_group;
826 n != (symtab_node)node;
827 n = n->symbol.same_comdat_group)
0ca9d009 828 /* If at least one of same comdat group functions is external,
829 all of them have to be, otherwise it is a front-end bug. */
7d0d0ce1 830 gcc_assert (DECL_EXTERNAL (n->symbol.decl));
c524ac5d 831#endif
cf951b1a 832 symtab_dissolve_same_comdat_group_list ((symtab_node) node);
0ca9d009 833 }
7d0d0ce1 834 gcc_assert ((!DECL_WEAK (node->symbol.decl)
835 && !DECL_COMDAT (node->symbol.decl))
836 || TREE_PUBLIC (node->symbol.decl)
f2526cce 837 || node->symbol.weakref
7d0d0ce1 838 || DECL_EXTERNAL (node->symbol.decl));
7dfe7ce5 839 if (cgraph_externally_visible_p (node, whole_program))
59dd4830 840 {
841 gcc_assert (!node->global.inlined_to);
7d0d0ce1 842 node->symbol.externally_visible = true;
59dd4830 843 }
844 else
6a1c0403 845 {
846 node->symbol.externally_visible = false;
847 node->symbol.forced_by_abi = false;
848 }
f2526cce 849 if (!node->symbol.externally_visible
850 && node->symbol.definition && !node->symbol.weakref
7d0d0ce1 851 && !DECL_EXTERNAL (node->symbol.decl))
f37a5008 852 {
7d0d0ce1 853 gcc_assert (whole_program || in_lto_p
854 || !TREE_PUBLIC (node->symbol.decl));
5c368d8a 855 node->symbol.unique_name = ((node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY
856 || node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
857 && TREE_PUBLIC (node->symbol.decl));
cf951b1a 858 symtab_make_decl_local (node->symbol.decl);
7d0d0ce1 859 node->symbol.resolution = LDPR_PREVAILING_DEF_IRONLY;
860 if (node->symbol.same_comdat_group)
c524ac5d 861 /* cgraph_externally_visible_p has already checked all other nodes
862 in the group and they will all be made local. We need to
863 dissolve the group at once so that the predicate does not
864 segfault though. */
cf951b1a 865 symtab_dissolve_same_comdat_group_list ((symtab_node) node);
f37a5008 866 }
91bf9d9a 867
868 if (node->thunk.thunk_p
7d0d0ce1 869 && TREE_PUBLIC (node->symbol.decl))
91bf9d9a 870 {
871 struct cgraph_node *decl_node = node;
872
c70f46b0 873 decl_node = cgraph_function_node (decl_node->callees->callee, NULL);
91bf9d9a 874
875 /* Thunks have the same visibility as function they are attached to.
dabebf7e 876 Make sure the C++ front end set this up properly. */
7d0d0ce1 877 if (DECL_ONE_ONLY (decl_node->symbol.decl))
91bf9d9a 878 {
7d0d0ce1 879 gcc_checking_assert (DECL_COMDAT (node->symbol.decl)
880 == DECL_COMDAT (decl_node->symbol.decl));
881 gcc_checking_assert (DECL_COMDAT_GROUP (node->symbol.decl)
882 == DECL_COMDAT_GROUP (decl_node->symbol.decl));
883 gcc_checking_assert (node->symbol.same_comdat_group);
91bf9d9a 884 }
7d0d0ce1 885 if (DECL_EXTERNAL (decl_node->symbol.decl))
886 DECL_EXTERNAL (node->symbol.decl) = 1;
91bf9d9a 887 }
f37a5008 888 }
7c455d87 889 FOR_EACH_DEFINED_FUNCTION (node)
44e82502 890 {
891 node->local.local = cgraph_local_node_p (node);
892
893 /* If we know that function can not be overwritten by a different semantics
894 and moreover its section can not be discarded, replace all direct calls
895 by calls to an nonoverwritable alias. This make dynamic linking
896 cheaper and enable more optimization.
897
898 TODO: We can also update virtual tables. */
899 if (node->callers && can_replace_by_local_alias ((symtab_node)node))
900 {
901 struct cgraph_node *alias = cgraph (symtab_nonoverwritable_alias ((symtab_node) node));
902
903 if (alias != node)
904 {
905 while (node->callers)
906 {
907 struct cgraph_edge *e = node->callers;
908
909 cgraph_redirect_edge_callee (e, alias);
910 if (!flag_wpa)
911 {
912 push_cfun (DECL_STRUCT_FUNCTION (e->caller->symbol.decl));
913 cgraph_redirect_edge_call_stmt_to_callee (e);
914 pop_cfun ();
915 }
916 }
917 }
918 }
919 }
7c455d87 920 FOR_EACH_VARIABLE (vnode)
930cff67 921 {
922 /* weak flag makes no sense on local variables. */
7d0d0ce1 923 gcc_assert (!DECL_WEAK (vnode->symbol.decl)
f2526cce 924 || vnode->symbol.weakref
7d0d0ce1 925 || TREE_PUBLIC (vnode->symbol.decl)
926 || DECL_EXTERNAL (vnode->symbol.decl));
930cff67 927 /* In several cases declarations can not be common:
928
929 - when declaration has initializer
930 - when it is in weak
931 - when it has specific section
932 - when it resides in non-generic address space.
933 - if declaration is local, it will get into .local common section
934 so common flag is not needed. Frontends still produce these in
935 certain cases, such as for:
936
937 static int a __attribute__ ((common))
938
939 Canonicalize things here and clear the redundant flag. */
7d0d0ce1 940 if (DECL_COMMON (vnode->symbol.decl)
941 && (!(TREE_PUBLIC (vnode->symbol.decl)
942 || DECL_EXTERNAL (vnode->symbol.decl))
943 || (DECL_INITIAL (vnode->symbol.decl)
944 && DECL_INITIAL (vnode->symbol.decl) != error_mark_node)
945 || DECL_WEAK (vnode->symbol.decl)
946 || DECL_SECTION_NAME (vnode->symbol.decl) != NULL
930cff67 947 || ! (ADDR_SPACE_GENERIC_P
7d0d0ce1 948 (TYPE_ADDR_SPACE (TREE_TYPE (vnode->symbol.decl))))))
949 DECL_COMMON (vnode->symbol.decl) = 0;
930cff67 950 }
7c455d87 951 FOR_EACH_DEFINED_VARIABLE (vnode)
f37a5008 952 {
15ca8f90 953 if (!vnode->symbol.definition)
e51ee2f1 954 continue;
7dfe7ce5 955 if (varpool_externally_visible_p (vnode))
7d0d0ce1 956 vnode->symbol.externally_visible = true;
59dd4830 957 else
6a1c0403 958 {
959 vnode->symbol.externally_visible = false;
960 vnode->symbol.forced_by_abi = false;
961 }
f2526cce 962 if (!vnode->symbol.externally_visible
963 && !vnode->symbol.weakref)
f37a5008 964 {
7d0d0ce1 965 gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->symbol.decl));
cf951b1a 966 symtab_make_decl_local (vnode->symbol.decl);
5c368d8a 967 vnode->symbol.unique_name = ((vnode->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY
968 || vnode->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
969 && TREE_PUBLIC (vnode->symbol.decl));
3e7775f6 970 if (vnode->symbol.same_comdat_group)
cf951b1a 971 symtab_dissolve_same_comdat_group_list ((symtab_node) vnode);
7d0d0ce1 972 vnode->symbol.resolution = LDPR_PREVAILING_DEF_IRONLY;
f37a5008 973 }
f37a5008 974 }
975
976 if (dump_file)
977 {
978 fprintf (dump_file, "\nMarking local functions:");
7c455d87 979 FOR_EACH_DEFINED_FUNCTION (node)
f37a5008 980 if (node->local.local)
981 fprintf (dump_file, " %s", cgraph_node_name (node));
982 fprintf (dump_file, "\n\n");
983 fprintf (dump_file, "\nMarking externally visible functions:");
7c455d87 984 FOR_EACH_DEFINED_FUNCTION (node)
7d0d0ce1 985 if (node->symbol.externally_visible)
f37a5008 986 fprintf (dump_file, " %s", cgraph_node_name (node));
987 fprintf (dump_file, "\n\n");
22671757 988 fprintf (dump_file, "\nMarking externally visible variables:");
7c455d87 989 FOR_EACH_DEFINED_VARIABLE (vnode)
7d0d0ce1 990 if (vnode->symbol.externally_visible)
22671757 991 fprintf (dump_file, " %s", varpool_node_name (vnode));
992 fprintf (dump_file, "\n\n");
f37a5008 993 }
994 cgraph_function_flags_ready = true;
a757b4dc 995 return 0;
f37a5008 996}
997
59dd4830 998/* Local function pass handling visibilities. This happens before LTO streaming
999 so in particular -fwhole-program should be ignored at this level. */
1000
1001static unsigned int
1002local_function_and_variable_visibility (void)
1003{
cbcf2791 1004 return function_and_variable_visibility (flag_whole_program && !flag_lto);
59dd4830 1005}
1006
48e1416a 1007struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility =
f37a5008 1008{
20099e35 1009 {
1010 SIMPLE_IPA_PASS,
f37a5008 1011 "visibility", /* name */
c7875731 1012 OPTGROUP_NONE, /* optinfo_flags */
f37a5008 1013 NULL, /* gate */
59dd4830 1014 local_function_and_variable_visibility,/* execute */
f37a5008 1015 NULL, /* sub */
1016 NULL, /* next */
1017 0, /* static_pass_number */
1018 TV_CGRAPHOPT, /* tv_id */
1019 0, /* properties_required */
1020 0, /* properties_provided */
1021 0, /* properties_destroyed */
1022 0, /* todo_flags_start */
ef3baff5 1023 TODO_remove_functions | TODO_dump_symtab /* todo_flags_finish */
20099e35 1024 }
f37a5008 1025};
13f90d63 1026
f8bfd7f7 1027/* Free inline summary. */
1028
1029static unsigned
1030free_inline_summary (void)
1031{
1032 inline_free_summary ();
1033 return 0;
1034}
1035
1036struct simple_ipa_opt_pass pass_ipa_free_inline_summary =
1037{
1038 {
1039 SIMPLE_IPA_PASS,
1040 "*free_inline_summary", /* name */
c7875731 1041 OPTGROUP_NONE, /* optinfo_flags */
f8bfd7f7 1042 NULL, /* gate */
1043 free_inline_summary, /* execute */
1044 NULL, /* sub */
1045 NULL, /* next */
1046 0, /* static_pass_number */
1047 TV_IPA_FREE_INLINE_SUMMARY, /* tv_id */
1048 0, /* properties_required */
1049 0, /* properties_provided */
1050 0, /* properties_destroyed */
1051 0, /* todo_flags_start */
ef3baff5 1052 0 /* todo_flags_finish */
f8bfd7f7 1053 }
1054};
1055
59dd4830 1056/* Do not re-run on ltrans stage. */
1057
1058static bool
1059gate_whole_program_function_and_variable_visibility (void)
1060{
1061 return !flag_ltrans;
1062}
1063
9d75589a 1064/* Bring functionss local at LTO time with -fwhole-program. */
59dd4830 1065
1066static unsigned int
1067whole_program_function_and_variable_visibility (void)
1068{
59dd4830 1069 function_and_variable_visibility (flag_whole_program);
023a28e1 1070 if (optimize)
1071 ipa_discover_readonly_nonaddressable_vars ();
59dd4830 1072 return 0;
1073}
1074
1075struct ipa_opt_pass_d pass_ipa_whole_program_visibility =
1076{
1077 {
1078 IPA_PASS,
1079 "whole-program", /* name */
c7875731 1080 OPTGROUP_NONE, /* optinfo_flags */
59dd4830 1081 gate_whole_program_function_and_variable_visibility,/* gate */
1082 whole_program_function_and_variable_visibility,/* execute */
1083 NULL, /* sub */
1084 NULL, /* next */
1085 0, /* static_pass_number */
1086 TV_CGRAPHOPT, /* tv_id */
1087 0, /* properties_required */
1088 0, /* properties_provided */
1089 0, /* properties_destroyed */
1090 0, /* todo_flags_start */
ef3baff5 1091 TODO_remove_functions | TODO_dump_symtab /* todo_flags_finish */
59dd4830 1092 },
1093 NULL, /* generate_summary */
1094 NULL, /* write_summary */
1095 NULL, /* read_summary */
ddc90d88 1096 NULL, /* write_optimization_summary */
1097 NULL, /* read_optimization_summary */
90464c8b 1098 NULL, /* stmt_fixup */
59dd4830 1099 0, /* TODOs */
1100 NULL, /* function_transform */
1101 NULL, /* variable_transform */
1102};
13f90d63 1103
9e179a64 1104/* Entry in the histogram. */
1105
1106struct histogram_entry
1107{
1108 gcov_type count;
1109 int time;
1110 int size;
1111};
1112
1113/* Histogram of profile values.
1114 The histogram is represented as an ordered vector of entries allocated via
1115 histogram_pool. During construction a separate hashtable is kept to lookup
1116 duplicate entries. */
1117
1118vec<histogram_entry *> histogram;
1119static alloc_pool histogram_pool;
1120
1121/* Hashtable support for storing SSA names hashed by their SSA_NAME_VAR. */
1122
1123struct histogram_hash : typed_noop_remove <histogram_entry>
1124{
1125 typedef histogram_entry value_type;
1126 typedef histogram_entry compare_type;
1127 static inline hashval_t hash (const value_type *);
1128 static inline int equal (const value_type *, const compare_type *);
1129};
1130
1131inline hashval_t
1132histogram_hash::hash (const histogram_entry *val)
1133{
1134 return val->count;
1135}
1136
1137inline int
1138histogram_hash::equal (const histogram_entry *val, const histogram_entry *val2)
1139{
1140 return val->count == val2->count;
1141}
1142
1143/* Account TIME and SIZE executed COUNT times into HISTOGRAM.
1144 HASHTABLE is the on-side hash kept to avoid duplicates. */
1145
1146static void
1147account_time_size (hash_table <histogram_hash> hashtable,
1148 vec<histogram_entry *> &histogram,
1149 gcov_type count, int time, int size)
1150{
1151 histogram_entry key = {count, 0, 0};
1152 histogram_entry **val = hashtable.find_slot (&key, INSERT);
1153
1154 if (!*val)
1155 {
1156 *val = (histogram_entry *) pool_alloc (histogram_pool);
1157 **val = key;
1158 histogram.safe_push (*val);
1159 }
1160 (*val)->time += time;
1161 (*val)->size += size;
1162}
1163
1164int
1165cmp_counts (const void *v1, const void *v2)
1166{
1167 const histogram_entry *h1 = *(const histogram_entry * const *)v1;
1168 const histogram_entry *h2 = *(const histogram_entry * const *)v2;
1169 if (h1->count < h2->count)
1170 return 1;
1171 if (h1->count > h2->count)
1172 return -1;
1173 return 0;
1174}
1175
1176/* Dump HISTOGRAM to FILE. */
1177
1178static void
1179dump_histogram (FILE *file, vec<histogram_entry *> histogram)
1180{
1181 unsigned int i;
1182 gcov_type overall_time = 0, cumulated_time = 0, cumulated_size = 0, overall_size = 0;
1183
1184 fprintf (dump_file, "Histogram:\n");
1185 for (i = 0; i < histogram.length (); i++)
1186 {
1187 overall_time += histogram[i]->count * histogram[i]->time;
1188 overall_size += histogram[i]->size;
1189 }
1190 if (!overall_time)
1191 overall_time = 1;
1192 if (!overall_size)
1193 overall_size = 1;
1194 for (i = 0; i < histogram.length (); i++)
1195 {
1196 cumulated_time += histogram[i]->count * histogram[i]->time;
1197 cumulated_size += histogram[i]->size;
1198 fprintf (file, " "HOST_WIDEST_INT_PRINT_DEC": time:%i (%2.2f) size:%i (%2.2f)\n",
1199 (HOST_WIDEST_INT) histogram[i]->count,
1200 histogram[i]->time,
1201 cumulated_time * 100.0 / overall_time,
1202 histogram[i]->size,
1203 cumulated_size * 100.0 / overall_size);
1204 }
1205}
1206
1207/* Collect histogram from CFG profiles. */
1208
1209static void
1210ipa_profile_generate_summary (void)
1211{
1212 struct cgraph_node *node;
1213 gimple_stmt_iterator gsi;
1214 hash_table <histogram_hash> hashtable;
1215 basic_block bb;
1216
1217 hashtable.create (10);
1218 histogram_pool = create_alloc_pool ("IPA histogram", sizeof (struct histogram_entry),
1219 10);
1220
1221 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
1222 FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->symbol.decl))
1223 {
1224 int time = 0;
1225 int size = 0;
1226 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1227 {
1228 time += estimate_num_insns (gsi_stmt (gsi), &eni_time_weights);
1229 size += estimate_num_insns (gsi_stmt (gsi), &eni_size_weights);
1230 }
1231 account_time_size (hashtable, histogram, bb->count, time, size);
1232 }
1233 hashtable.dispose ();
1234 histogram.qsort (cmp_counts);
1235}
1236
1237/* Serialize the ipa info for lto. */
1238
1239static void
1240ipa_profile_write_summary (void)
1241{
1242 struct lto_simple_output_block *ob
1243 = lto_create_simple_output_block (LTO_section_ipa_profile);
1244 unsigned int i;
1245
1246 streamer_write_uhwi_stream (ob->main_stream, histogram.length());
1247 for (i = 0; i < histogram.length (); i++)
1248 {
1249 streamer_write_gcov_count_stream (ob->main_stream, histogram[i]->count);
1250 streamer_write_uhwi_stream (ob->main_stream, histogram[i]->time);
1251 streamer_write_uhwi_stream (ob->main_stream, histogram[i]->size);
1252 }
1253 lto_destroy_simple_output_block (ob);
1254}
1255
1256/* Deserialize the ipa info for lto. */
1257
1258static void
1259ipa_profile_read_summary (void)
1260{
1261 struct lto_file_decl_data ** file_data_vec
1262 = lto_get_file_decl_data ();
1263 struct lto_file_decl_data * file_data;
1264 hash_table <histogram_hash> hashtable;
1265 int j = 0;
1266
1267 hashtable.create (10);
1268 histogram_pool = create_alloc_pool ("IPA histogram", sizeof (struct histogram_entry),
1269 10);
1270
1271 while ((file_data = file_data_vec[j++]))
1272 {
1273 const char *data;
1274 size_t len;
1275 struct lto_input_block *ib
1276 = lto_create_simple_input_block (file_data,
1277 LTO_section_ipa_profile,
1278 &data, &len);
1279 if (ib)
1280 {
1281 unsigned int num = streamer_read_uhwi (ib);
1282 unsigned int n;
1283 for (n = 0; n < num; n++)
1284 {
1285 gcov_type count = streamer_read_gcov_count (ib);
1286 int time = streamer_read_uhwi (ib);
1287 int size = streamer_read_uhwi (ib);
1288 account_time_size (hashtable, histogram,
1289 count, time, size);
1290 }
1291 lto_destroy_simple_input_block (file_data,
1292 LTO_section_ipa_profile,
1293 ib, data, len);
1294 }
1295 }
1296 hashtable.dispose ();
1297 histogram.qsort (cmp_counts);
1298}
0cddb138 1299
4e2db0ad 1300/* Simple ipa profile pass propagating frequencies across the callgraph. */
1301
1302static unsigned int
1303ipa_profile (void)
1304{
1305 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
1306 struct cgraph_edge *e;
1307 int order_pos;
1308 bool something_changed = false;
1309 int i;
9e179a64 1310 gcov_type overall_time = 0, cutoff = 0, cumulated = 0, overall_size = 0;
1311
1312 if (dump_file)
1313 dump_histogram (dump_file, histogram);
1314 for (i = 0; i < (int)histogram.length (); i++)
1315 {
1316 overall_time += histogram[i]->count * histogram[i]->time;
1317 overall_size += histogram[i]->size;
1318 }
1319 if (overall_time)
1320 {
1321 gcov_type threshold;
1322
1323 gcc_assert (overall_size);
1324 if (dump_file)
1325 {
1326 gcov_type min, cumulated_time = 0, cumulated_size = 0;
1327
1328 fprintf (dump_file, "Overall time: "HOST_WIDEST_INT_PRINT_DEC"\n",
1329 (HOST_WIDEST_INT)overall_time);
1330 min = get_hot_bb_threshold ();
1331 for (i = 0; i < (int)histogram.length () && histogram[i]->count >= min;
1332 i++)
1333 {
1334 cumulated_time += histogram[i]->count * histogram[i]->time;
1335 cumulated_size += histogram[i]->size;
1336 }
1337 fprintf (dump_file, "GCOV min count: "HOST_WIDEST_INT_PRINT_DEC
1338 " Time:%3.2f%% Size:%3.2f%%\n",
1339 (HOST_WIDEST_INT)min,
1340 cumulated_time * 100.0 / overall_time,
1341 cumulated_size * 100.0 / overall_size);
1342 }
1343 cutoff = (overall_time * PARAM_VALUE (HOT_BB_COUNT_WS_PERMILLE) + 500) / 1000;
1344 threshold = 0;
1345 for (i = 0; cumulated < cutoff; i++)
1346 {
1347 cumulated += histogram[i]->count * histogram[i]->time;
1348 threshold = histogram[i]->count;
1349 }
1350 if (!threshold)
1351 threshold = 1;
1352 if (dump_file)
1353 {
1354 gcov_type cumulated_time = 0, cumulated_size = 0;
1355
1356 for (i = 0;
1357 i < (int)histogram.length () && histogram[i]->count >= threshold;
1358 i++)
1359 {
1360 cumulated_time += histogram[i]->count * histogram[i]->time;
1361 cumulated_size += histogram[i]->size;
1362 }
1363 fprintf (dump_file, "Determined min count: "HOST_WIDEST_INT_PRINT_DEC
1364 " Time:%3.2f%% Size:%3.2f%%\n",
1365 (HOST_WIDEST_INT)threshold,
1366 cumulated_time * 100.0 / overall_time,
1367 cumulated_size * 100.0 / overall_size);
1368 }
1369 if (threshold > get_hot_bb_threshold ()
1370 || in_lto_p)
1371 {
1372 if (dump_file)
1373 fprintf (dump_file, "Threshold updated.\n");
1374 set_hot_bb_threshold (threshold);
1375 }
1376 }
1377 histogram.release();
1378 free_alloc_pool (histogram_pool);
4e2db0ad 1379
7771d558 1380 order_pos = ipa_reverse_postorder (order);
4e2db0ad 1381 for (i = order_pos - 1; i >= 0; i--)
1382 {
1383 if (order[i]->local.local && cgraph_propagate_frequency (order[i]))
1384 {
1385 for (e = order[i]->callees; e; e = e->next_callee)
7d0d0ce1 1386 if (e->callee->local.local && !e->callee->symbol.aux)
4e2db0ad 1387 {
1388 something_changed = true;
7d0d0ce1 1389 e->callee->symbol.aux = (void *)1;
4e2db0ad 1390 }
1391 }
7d0d0ce1 1392 order[i]->symbol.aux = NULL;
4e2db0ad 1393 }
1394
1395 while (something_changed)
1396 {
1397 something_changed = false;
1398 for (i = order_pos - 1; i >= 0; i--)
1399 {
7d0d0ce1 1400 if (order[i]->symbol.aux && cgraph_propagate_frequency (order[i]))
4e2db0ad 1401 {
1402 for (e = order[i]->callees; e; e = e->next_callee)
7d0d0ce1 1403 if (e->callee->local.local && !e->callee->symbol.aux)
4e2db0ad 1404 {
1405 something_changed = true;
7d0d0ce1 1406 e->callee->symbol.aux = (void *)1;
4e2db0ad 1407 }
1408 }
7d0d0ce1 1409 order[i]->symbol.aux = NULL;
4e2db0ad 1410 }
1411 }
1412 free (order);
1413 return 0;
1414}
1415
1416static bool
1417gate_ipa_profile (void)
1418{
1419 return flag_ipa_profile;
1420}
1421
1422struct ipa_opt_pass_d pass_ipa_profile =
1423{
1424 {
1425 IPA_PASS,
855c9b82 1426 "profile_estimate", /* name */
c7875731 1427 OPTGROUP_NONE, /* optinfo_flags */
4e2db0ad 1428 gate_ipa_profile, /* gate */
1429 ipa_profile, /* execute */
1430 NULL, /* sub */
1431 NULL, /* next */
1432 0, /* static_pass_number */
1433 TV_IPA_PROFILE, /* tv_id */
1434 0, /* properties_required */
1435 0, /* properties_provided */
1436 0, /* properties_destroyed */
1437 0, /* todo_flags_start */
1438 0 /* todo_flags_finish */
1439 },
9e179a64 1440 ipa_profile_generate_summary, /* generate_summary */
1441 ipa_profile_write_summary, /* write_summary */
1442 ipa_profile_read_summary, /* read_summary */
4e2db0ad 1443 NULL, /* write_optimization_summary */
1444 NULL, /* read_optimization_summary */
1445 NULL, /* stmt_fixup */
1446 0, /* TODOs */
1447 NULL, /* function_transform */
1448 NULL /* variable_transform */
1449};
a53e7471 1450
1451/* Generate and emit a static constructor or destructor. WHICH must
1452 be one of 'I' (for a constructor) or 'D' (for a destructor). BODY
1453 is a STATEMENT_LIST containing GENERIC statements. PRIORITY is the
62510893 1454 initialization priority for this constructor or destructor.
a53e7471 1455
62510893 1456 FINAL specify whether the externally visible name for collect2 should
1457 be produced. */
1458
1459static void
1460cgraph_build_static_cdtor_1 (char which, tree body, int priority, bool final)
a53e7471 1461{
1462 static int counter = 0;
1463 char which_buf[16];
1464 tree decl, name, resdecl;
1465
1466 /* The priority is encoded in the constructor or destructor name.
1467 collect2 will sort the names and arrange that they are called at
1468 program startup. */
62510893 1469 if (final)
1470 sprintf (which_buf, "%c_%.5d_%d", which, priority, counter++);
1471 else
1472 /* Proudce sane name but one not recognizable by collect2, just for the
1473 case we fail to inline the function. */
1474 sprintf (which_buf, "sub_%c_%.5d_%d", which, priority, counter++);
a53e7471 1475 name = get_file_function_name (which_buf);
1476
1477 decl = build_decl (input_location, FUNCTION_DECL, name,
1478 build_function_type_list (void_type_node, NULL_TREE));
1479 current_function_decl = decl;
1480
1481 resdecl = build_decl (input_location,
1482 RESULT_DECL, NULL_TREE, void_type_node);
1483 DECL_ARTIFICIAL (resdecl) = 1;
1484 DECL_RESULT (decl) = resdecl;
1485 DECL_CONTEXT (resdecl) = decl;
1486
1487 allocate_struct_function (decl, false);
1488
1489 TREE_STATIC (decl) = 1;
1490 TREE_USED (decl) = 1;
1491 DECL_ARTIFICIAL (decl) = 1;
1492 DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
1493 DECL_SAVED_TREE (decl) = body;
62510893 1494 if (!targetm.have_ctors_dtors && final)
a53e7471 1495 {
1496 TREE_PUBLIC (decl) = 1;
1497 DECL_PRESERVE_P (decl) = 1;
1498 }
1499 DECL_UNINLINABLE (decl) = 1;
1500
1501 DECL_INITIAL (decl) = make_node (BLOCK);
1502 TREE_USED (DECL_INITIAL (decl)) = 1;
1503
1504 DECL_SOURCE_LOCATION (decl) = input_location;
1505 cfun->function_end_locus = input_location;
1506
1507 switch (which)
1508 {
1509 case 'I':
1510 DECL_STATIC_CONSTRUCTOR (decl) = 1;
1511 decl_init_priority_insert (decl, priority);
1512 break;
1513 case 'D':
1514 DECL_STATIC_DESTRUCTOR (decl) = 1;
1515 decl_fini_priority_insert (decl, priority);
1516 break;
1517 default:
1518 gcc_unreachable ();
1519 }
1520
1521 gimplify_function_tree (decl);
1522
1523 cgraph_add_new_function (decl, false);
1524
1525 set_cfun (NULL);
1526 current_function_decl = NULL;
1527}
1528
62510893 1529/* Generate and emit a static constructor or destructor. WHICH must
1530 be one of 'I' (for a constructor) or 'D' (for a destructor). BODY
1531 is a STATEMENT_LIST containing GENERIC statements. PRIORITY is the
1532 initialization priority for this constructor or destructor. */
1533
1534void
1535cgraph_build_static_cdtor (char which, tree body, int priority)
1536{
1537 cgraph_build_static_cdtor_1 (which, body, priority, false);
1538}
a53e7471 1539
1540/* A vector of FUNCTION_DECLs declared as static constructors. */
f1f41a6c 1541static vec<tree> static_ctors;
a53e7471 1542/* A vector of FUNCTION_DECLs declared as static destructors. */
f1f41a6c 1543static vec<tree> static_dtors;
a53e7471 1544
1545/* When target does not have ctors and dtors, we call all constructor
1546 and destructor by special initialization/destruction function
1547 recognized by collect2.
1548
1549 When we are going to build this function, collect all constructors and
1550 destructors and turn them into normal functions. */
1551
1552static void
1553record_cdtor_fn (struct cgraph_node *node)
1554{
7d0d0ce1 1555 if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl))
f1f41a6c 1556 static_ctors.safe_push (node->symbol.decl);
7d0d0ce1 1557 if (DECL_STATIC_DESTRUCTOR (node->symbol.decl))
f1f41a6c 1558 static_dtors.safe_push (node->symbol.decl);
7d0d0ce1 1559 node = cgraph_get_node (node->symbol.decl);
1560 DECL_DISREGARD_INLINE_LIMITS (node->symbol.decl) = 1;
a53e7471 1561}
1562
1563/* Define global constructors/destructor functions for the CDTORS, of
1564 which they are LEN. The CDTORS are sorted by initialization
1565 priority. If CTOR_P is true, these are constructors; otherwise,
1566 they are destructors. */
1567
1568static void
f1f41a6c 1569build_cdtor (bool ctor_p, vec<tree> cdtors)
a53e7471 1570{
1571 size_t i,j;
f1f41a6c 1572 size_t len = cdtors.length ();
a53e7471 1573
1574 i = 0;
1575 while (i < len)
1576 {
1577 tree body;
1578 tree fn;
1579 priority_type priority;
1580
1581 priority = 0;
1582 body = NULL_TREE;
1583 j = i;
1584 do
1585 {
1586 priority_type p;
f1f41a6c 1587 fn = cdtors[j];
a53e7471 1588 p = ctor_p ? DECL_INIT_PRIORITY (fn) : DECL_FINI_PRIORITY (fn);
1589 if (j == i)
1590 priority = p;
1591 else if (p != priority)
1592 break;
1593 j++;
1594 }
1595 while (j < len);
1596
d2435fb0 1597 /* When there is only one cdtor and target supports them, do nothing. */
a53e7471 1598 if (j == i + 1
1599 && targetm.have_ctors_dtors)
1600 {
1601 i++;
1602 continue;
1603 }
1604 /* Find the next batch of constructors/destructors with the same
1605 initialization priority. */
d2435fb0 1606 for (;i < j; i++)
a53e7471 1607 {
a53e7471 1608 tree call;
f1f41a6c 1609 fn = cdtors[i];
a53e7471 1610 call = build_call_expr (fn, 0);
1611 if (ctor_p)
1612 DECL_STATIC_CONSTRUCTOR (fn) = 0;
1613 else
1614 DECL_STATIC_DESTRUCTOR (fn) = 0;
1615 /* We do not want to optimize away pure/const calls here.
1616 When optimizing, these should be already removed, when not
1617 optimizing, we want user to be able to breakpoint in them. */
1618 TREE_SIDE_EFFECTS (call) = 1;
1619 append_to_statement_list (call, &body);
a53e7471 1620 }
a53e7471 1621 gcc_assert (body != NULL_TREE);
1622 /* Generate a function to call all the function of like
1623 priority. */
62510893 1624 cgraph_build_static_cdtor_1 (ctor_p ? 'I' : 'D', body, priority, true);
a53e7471 1625 }
1626}
1627
1628/* Comparison function for qsort. P1 and P2 are actually of type
1629 "tree *" and point to static constructors. DECL_INIT_PRIORITY is
1630 used to determine the sort order. */
1631
1632static int
1633compare_ctor (const void *p1, const void *p2)
1634{
1635 tree f1;
1636 tree f2;
1637 int priority1;
1638 int priority2;
1639
1640 f1 = *(const tree *)p1;
1641 f2 = *(const tree *)p2;
1642 priority1 = DECL_INIT_PRIORITY (f1);
1643 priority2 = DECL_INIT_PRIORITY (f2);
1644
1645 if (priority1 < priority2)
1646 return -1;
1647 else if (priority1 > priority2)
1648 return 1;
1649 else
1650 /* Ensure a stable sort. Constructors are executed in backwarding
1651 order to make LTO initialize braries first. */
1652 return DECL_UID (f2) - DECL_UID (f1);
1653}
1654
1655/* Comparison function for qsort. P1 and P2 are actually of type
1656 "tree *" and point to static destructors. DECL_FINI_PRIORITY is
1657 used to determine the sort order. */
1658
1659static int
1660compare_dtor (const void *p1, const void *p2)
1661{
1662 tree f1;
1663 tree f2;
1664 int priority1;
1665 int priority2;
1666
1667 f1 = *(const tree *)p1;
1668 f2 = *(const tree *)p2;
1669 priority1 = DECL_FINI_PRIORITY (f1);
1670 priority2 = DECL_FINI_PRIORITY (f2);
1671
1672 if (priority1 < priority2)
1673 return -1;
1674 else if (priority1 > priority2)
1675 return 1;
1676 else
1677 /* Ensure a stable sort. */
1678 return DECL_UID (f1) - DECL_UID (f2);
1679}
1680
1681/* Generate functions to call static constructors and destructors
1682 for targets that do not support .ctors/.dtors sections. These
1683 functions have magic names which are detected by collect2. */
1684
1685static void
1686build_cdtor_fns (void)
1687{
f1f41a6c 1688 if (!static_ctors.is_empty ())
a53e7471 1689 {
1690 gcc_assert (!targetm.have_ctors_dtors || in_lto_p);
f1f41a6c 1691 static_ctors.qsort (compare_ctor);
d2435fb0 1692 build_cdtor (/*ctor_p=*/true, static_ctors);
a53e7471 1693 }
1694
f1f41a6c 1695 if (!static_dtors.is_empty ())
a53e7471 1696 {
1697 gcc_assert (!targetm.have_ctors_dtors || in_lto_p);
f1f41a6c 1698 static_dtors.qsort (compare_dtor);
d2435fb0 1699 build_cdtor (/*ctor_p=*/false, static_dtors);
a53e7471 1700 }
1701}
1702
1703/* Look for constructors and destructors and produce function calling them.
1704 This is needed for targets not supporting ctors or dtors, but we perform the
9d75589a 1705 transformation also at linktime to merge possibly numerous
a53e7471 1706 constructors/destructors into single function to improve code locality and
1707 reduce size. */
1708
1709static unsigned int
1710ipa_cdtor_merge (void)
1711{
1712 struct cgraph_node *node;
7c455d87 1713 FOR_EACH_DEFINED_FUNCTION (node)
1714 if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl)
1715 || DECL_STATIC_DESTRUCTOR (node->symbol.decl))
a53e7471 1716 record_cdtor_fn (node);
1717 build_cdtor_fns ();
f1f41a6c 1718 static_ctors.release ();
1719 static_dtors.release ();
a53e7471 1720 return 0;
1721}
1722
1723/* Perform the pass when we have no ctors/dtors support
1724 or at LTO time to merge multiple constructors into single
1725 function. */
1726
1727static bool
1728gate_ipa_cdtor_merge (void)
1729{
1730 return !targetm.have_ctors_dtors || (optimize && in_lto_p);
1731}
1732
1733struct ipa_opt_pass_d pass_ipa_cdtor_merge =
1734{
1735 {
1736 IPA_PASS,
1737 "cdtor", /* name */
c7875731 1738 OPTGROUP_NONE, /* optinfo_flags */
a53e7471 1739 gate_ipa_cdtor_merge, /* gate */
1740 ipa_cdtor_merge, /* execute */
1741 NULL, /* sub */
1742 NULL, /* next */
1743 0, /* static_pass_number */
1744 TV_CGRAPHOPT, /* tv_id */
1745 0, /* properties_required */
1746 0, /* properties_provided */
1747 0, /* properties_destroyed */
1748 0, /* todo_flags_start */
1749 0 /* todo_flags_finish */
1750 },
1751 NULL, /* generate_summary */
1752 NULL, /* write_summary */
1753 NULL, /* read_summary */
1754 NULL, /* write_optimization_summary */
1755 NULL, /* read_optimization_summary */
1756 NULL, /* stmt_fixup */
1757 0, /* TODOs */
1758 NULL, /* function_transform */
1759 NULL /* variable_transform */
1760};