PR sanitizer/59009
[official-gcc.git] / gcc / ipa-reference.c
blobae8ba3c651fd4825e5aaf71a9edad37a0a1bfb2b
1 /* Callgraph based analysis of static variables.
2 Copyright (C) 2004-2013 Free Software Foundation, Inc.
3 Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
5 This file is part of GCC.
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 3, or (at your option) any later
10 version.
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.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* This file gathers information about how variables whose scope is
22 confined to the compilation unit are used.
24 The transitive call site specific clobber effects are computed
25 for the variables whose scope is contained within this compilation
26 unit.
28 First each function and static variable initialization is analyzed
29 to determine which local static variables are either read, written,
30 or have their address taken. Any local static that has its address
31 taken is removed from consideration. Once the local read and
32 writes are determined, a transitive closure of this information is
33 performed over the call graph to determine the worst case set of
34 side effects of each call. In later parts of the compiler, these
35 local and global sets are examined to make the call clobbering less
36 traumatic, promote some statics to registers, and improve aliasing
37 information. */
39 #include "config.h"
40 #include "system.h"
41 #include "coretypes.h"
42 #include "tm.h"
43 #include "tree.h"
44 #include "gimple.h"
45 #include "tree-inline.h"
46 #include "tree-pass.h"
47 #include "pointer-set.h"
48 #include "splay-tree.h"
49 #include "ggc.h"
50 #include "ipa-utils.h"
51 #include "ipa-reference.h"
52 #include "flags.h"
53 #include "diagnostic.h"
54 #include "data-streamer.h"
55 #include "lto-streamer.h"
57 static void remove_node_data (struct cgraph_node *node,
58 void *data ATTRIBUTE_UNUSED);
59 static void duplicate_node_data (struct cgraph_node *src,
60 struct cgraph_node *dst,
61 void *data ATTRIBUTE_UNUSED);
63 /* The static variables defined within the compilation unit that are
64 loaded or stored directly by function that owns this structure. */
66 struct ipa_reference_local_vars_info_d
68 bitmap statics_read;
69 bitmap statics_written;
72 /* Statics that are read and written by some set of functions. The
73 local ones are based on the loads and stores local to the function.
74 The global ones are based on the local info as well as the
75 transitive closure of the functions that are called. */
77 struct ipa_reference_global_vars_info_d
79 bitmap statics_read;
80 bitmap statics_written;
83 /* Information we save about every function after ipa-reference is completed. */
85 struct ipa_reference_optimization_summary_d
87 bitmap statics_not_read;
88 bitmap statics_not_written;
91 typedef struct ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t;
92 typedef struct ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t;
93 typedef struct ipa_reference_optimization_summary_d *ipa_reference_optimization_summary_t;
95 struct ipa_reference_vars_info_d
97 struct ipa_reference_local_vars_info_d local;
98 struct ipa_reference_global_vars_info_d global;
101 typedef struct ipa_reference_vars_info_d *ipa_reference_vars_info_t;
103 /* This splay tree contains all of the static variables that are
104 being considered by the compilation level alias analysis. */
105 static splay_tree reference_vars_to_consider;
107 /* Set of all interesting module statics. A bit is set for every module
108 static we are considering. This is added to the local info when asm
109 code is found that clobbers all memory. */
110 static bitmap all_module_statics;
112 /* Obstack holding bitmaps of local analysis (live from analysis to
113 propagation) */
114 static bitmap_obstack local_info_obstack;
115 /* Obstack holding global analysis live forever. */
116 static bitmap_obstack optimization_summary_obstack;
118 /* Holders of ipa cgraph hooks: */
119 static struct cgraph_2node_hook_list *node_duplication_hook_holder;
120 static struct cgraph_node_hook_list *node_removal_hook_holder;
122 /* Vector where the reference var infos are actually stored.
123 Indexed by UID of call graph nodes. */
124 static vec<ipa_reference_vars_info_t> ipa_reference_vars_vector;
126 static vec<ipa_reference_optimization_summary_t> ipa_reference_opt_sum_vector;
128 /* Return the ipa_reference_vars structure starting from the cgraph NODE. */
129 static inline ipa_reference_vars_info_t
130 get_reference_vars_info (struct cgraph_node *node)
132 if (!ipa_reference_vars_vector.exists ()
133 || ipa_reference_vars_vector.length () <= (unsigned int) node->uid)
134 return NULL;
135 return ipa_reference_vars_vector[node->uid];
138 /* Return the ipa_reference_vars structure starting from the cgraph NODE. */
139 static inline ipa_reference_optimization_summary_t
140 get_reference_optimization_summary (struct cgraph_node *node)
142 if (!ipa_reference_opt_sum_vector.exists ()
143 || (ipa_reference_opt_sum_vector.length () <= (unsigned int) node->uid))
144 return NULL;
145 return ipa_reference_opt_sum_vector[node->uid];
148 /* Return the ipa_reference_vars structure starting from the cgraph NODE. */
149 static inline void
150 set_reference_vars_info (struct cgraph_node *node,
151 ipa_reference_vars_info_t info)
153 if (!ipa_reference_vars_vector.exists ()
154 || ipa_reference_vars_vector.length () <= (unsigned int) node->uid)
155 ipa_reference_vars_vector.safe_grow_cleared (node->uid + 1);
156 ipa_reference_vars_vector[node->uid] = info;
159 /* Return the ipa_reference_vars structure starting from the cgraph NODE. */
160 static inline void
161 set_reference_optimization_summary (struct cgraph_node *node,
162 ipa_reference_optimization_summary_t info)
164 if (!ipa_reference_opt_sum_vector.exists ()
165 || (ipa_reference_opt_sum_vector.length () <= (unsigned int) node->uid))
166 ipa_reference_opt_sum_vector.safe_grow_cleared (node->uid + 1);
167 ipa_reference_opt_sum_vector[node->uid] = info;
170 /* Return a bitmap indexed by DECL_UID for the static variables that
171 are *not* read during the execution of the function FN. Returns
172 NULL if no data is available. */
174 bitmap
175 ipa_reference_get_not_read_global (struct cgraph_node *fn)
177 ipa_reference_optimization_summary_t info =
178 get_reference_optimization_summary (cgraph_function_node (fn, NULL));
179 if (info)
180 return info->statics_not_read;
181 else if (flags_from_decl_or_type (fn->decl) & ECF_LEAF)
182 return all_module_statics;
183 else
184 return NULL;
187 /* Return a bitmap indexed by DECL_UID for the static variables that
188 are *not* written during the execution of the function FN. Note
189 that variables written may or may not be read during the function
190 call. Returns NULL if no data is available. */
192 bitmap
193 ipa_reference_get_not_written_global (struct cgraph_node *fn)
195 ipa_reference_optimization_summary_t info =
196 get_reference_optimization_summary (fn);
197 if (info)
198 return info->statics_not_written;
199 else if (flags_from_decl_or_type (fn->decl) & ECF_LEAF)
200 return all_module_statics;
201 else
202 return NULL;
207 /* Add VAR to all_module_statics and the two
208 reference_vars_to_consider* sets. */
210 static inline void
211 add_static_var (tree var)
213 int uid = DECL_UID (var);
214 gcc_assert (TREE_CODE (var) == VAR_DECL);
215 if (dump_file)
216 splay_tree_insert (reference_vars_to_consider,
217 uid, (splay_tree_value)var);
218 bitmap_set_bit (all_module_statics, uid);
221 /* Return true if the variable T is the right kind of static variable to
222 perform compilation unit scope escape analysis. */
224 static inline bool
225 is_proper_for_analysis (tree t)
227 /* If the variable has the "used" attribute, treat it as if it had a
228 been touched by the devil. */
229 if (DECL_PRESERVE_P (t))
230 return false;
232 /* Do not want to do anything with volatile except mark any
233 function that uses one to be not const or pure. */
234 if (TREE_THIS_VOLATILE (t))
235 return false;
237 /* We do not need to analyze readonly vars, we already know they do not
238 alias. */
239 if (TREE_READONLY (t))
240 return false;
242 /* This is a variable we care about. Check if we have seen it
243 before, and if not add it the set of variables we care about. */
244 if (all_module_statics
245 && !bitmap_bit_p (all_module_statics, DECL_UID (t)))
246 add_static_var (t);
248 return true;
251 /* Lookup the tree node for the static variable that has UID and
252 convert the name to a string for debugging. */
254 static const char *
255 get_static_name (int index)
257 splay_tree_node stn =
258 splay_tree_lookup (reference_vars_to_consider, index);
259 return fndecl_name ((tree)(stn->value));
262 /* Dump a set of static vars to FILE. */
263 static void
264 dump_static_vars_set_to_file (FILE *f, bitmap set)
266 unsigned int index;
267 bitmap_iterator bi;
268 if (set == NULL)
269 return;
270 else if (set == all_module_statics)
271 fprintf (f, "ALL");
272 else
273 EXECUTE_IF_SET_IN_BITMAP (set, 0, index, bi)
275 fprintf (f, "%s ", get_static_name (index));
279 /* Compute X |= Y, taking into account the possibility that
280 either X or Y is already the maximum set.
281 Return true if X is the maximum set after taking the union with Y. */
283 static bool
284 union_static_var_sets (bitmap &x, bitmap y)
286 if (x != all_module_statics)
288 if (y == all_module_statics)
290 BITMAP_FREE (x);
291 x = all_module_statics;
293 else if (bitmap_ior_into (x, y))
295 /* The union may have reduced X to the maximum set.
296 In that case, we want to make that visible explicitly.
297 Even though bitmap_equal_p can be very expensive, it
298 turns out to be an overall win to check this here for
299 an LTO bootstrap of GCC itself. Liberally extrapoliate
300 that result to be applicable to all cases. */
301 if (bitmap_equal_p (x, all_module_statics))
303 BITMAP_FREE (x);
304 x = all_module_statics;
308 return x == all_module_statics;
311 /* Compute X &= Y, taking into account the possibility that
312 X may become the maximum set. */
314 static bool
315 intersect_static_var_sets (bitmap &x, bitmap y)
317 if (x != all_module_statics)
319 bitmap_and_into (x, y);
320 /* As with union_static_var_sets, reducing to the maximum
321 set as early as possible is an overall win. */
322 if (bitmap_equal_p (x, all_module_statics))
324 BITMAP_FREE (x);
325 x = all_module_statics;
328 return x == all_module_statics;
331 /* Return a copy of SET on the bitmap obstack containing SET.
332 But if SET is NULL or the maximum set, return that instead. */
334 static bitmap
335 copy_static_var_set (bitmap set)
337 if (set == NULL || set == all_module_statics)
338 return set;
339 bitmap_obstack *o = set->obstack;
340 gcc_checking_assert (o);
341 bitmap copy = BITMAP_ALLOC (o);
342 bitmap_copy (copy, set);
343 return copy;
346 /* Compute the union all of the statics read and written by every callee of X
347 into X_GLOBAL->statics_read and X_GLOBAL->statics_written. X_GLOBAL is
348 actually the set representing the cycle containing X. If the read and
349 written sets of X_GLOBAL has been reduced to the maximum set, we don't
350 have to look at the remaining callees. */
352 static void
353 propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x)
355 struct cgraph_edge *e;
356 bool read_all = x_global->statics_read == all_module_statics;
357 bool write_all = x_global->statics_written == all_module_statics;
358 for (e = x->callees;
359 e && !(read_all && write_all);
360 e = e->next_callee)
362 enum availability avail;
363 struct cgraph_node *y = cgraph_function_node (e->callee, &avail);
364 if (!y)
365 continue;
367 /* Only look into nodes we can propagate something. */
368 int flags = flags_from_decl_or_type (y->decl);
369 if (avail > AVAIL_OVERWRITABLE
370 || (avail == AVAIL_OVERWRITABLE && (flags & ECF_LEAF)))
372 if (get_reference_vars_info (y))
374 ipa_reference_vars_info_t y_info = get_reference_vars_info (y);
375 ipa_reference_global_vars_info_t y_global = &y_info->global;
377 /* Calls in the current cycle do not have their global set
378 computed yet (but everything else does because we're
379 visiting nodes in topological order). */
380 if (!y_global->statics_read)
381 continue;
383 /* If the function is const, it reads no memory even if it
384 seems so to local analysis. */
385 if (flags & ECF_CONST)
386 continue;
388 union_static_var_sets (x_global->statics_read,
389 y_global->statics_read);
391 /* If the function is pure, it has no stores even if it
392 seems so to local analysis. If we cannot return from
393 the function, we can safely ignore the call. */
394 if ((flags & ECF_PURE)
395 || cgraph_edge_cannot_lead_to_return (e))
396 continue;
398 union_static_var_sets (x_global->statics_written,
399 y_global->statics_written);
401 else
402 gcc_unreachable ();
407 /* The init routine for analyzing global static variable usage. See
408 comments at top for description. */
409 static void
410 ipa_init (void)
412 static bool init_p = false;
414 if (init_p)
415 return;
417 init_p = true;
419 if (dump_file)
420 reference_vars_to_consider = splay_tree_new (splay_tree_compare_ints, 0, 0);
422 bitmap_obstack_initialize (&local_info_obstack);
423 bitmap_obstack_initialize (&optimization_summary_obstack);
424 all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack);
426 node_removal_hook_holder =
427 cgraph_add_node_removal_hook (&remove_node_data, NULL);
428 node_duplication_hook_holder =
429 cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
433 /* Set up the persistent info for FN. */
435 static ipa_reference_local_vars_info_t
436 init_function_info (struct cgraph_node *fn)
438 ipa_reference_vars_info_t info
439 = XCNEW (struct ipa_reference_vars_info_d);
441 /* Add the info to the tree's annotation. */
442 set_reference_vars_info (fn, info);
444 info->local.statics_read = BITMAP_ALLOC (&local_info_obstack);
445 info->local.statics_written = BITMAP_ALLOC (&local_info_obstack);
447 return &info->local;
451 /* This is the main routine for finding the reference patterns for
452 global variables within a function FN. */
454 static void
455 analyze_function (struct cgraph_node *fn)
457 ipa_reference_local_vars_info_t local;
458 struct ipa_ref *ref;
459 int i;
460 tree var;
462 local = init_function_info (fn);
463 for (i = 0; ipa_ref_list_reference_iterate (&fn->ref_list, i, ref); i++)
465 if (!is_a <varpool_node> (ref->referred))
466 continue;
467 var = ipa_ref_varpool_node (ref)->decl;
468 if (!is_proper_for_analysis (var))
469 continue;
470 switch (ref->use)
472 case IPA_REF_LOAD:
473 bitmap_set_bit (local->statics_read, DECL_UID (var));
474 break;
475 case IPA_REF_STORE:
476 if (ipa_ref_cannot_lead_to_return (ref))
477 break;
478 bitmap_set_bit (local->statics_written, DECL_UID (var));
479 break;
480 case IPA_REF_ADDR:
481 break;
485 if (cgraph_node_cannot_return (fn))
486 bitmap_clear (local->statics_written);
490 /* Called when new clone is inserted to callgraph late. */
492 static void
493 duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
494 void *data ATTRIBUTE_UNUSED)
496 ipa_reference_optimization_summary_t ginfo;
497 ipa_reference_optimization_summary_t dst_ginfo;
499 ginfo = get_reference_optimization_summary (src);
500 if (!ginfo)
501 return;
502 dst_ginfo = XCNEW (struct ipa_reference_optimization_summary_d);
503 set_reference_optimization_summary (dst, dst_ginfo);
504 dst_ginfo->statics_not_read =
505 copy_static_var_set (ginfo->statics_not_read);
506 dst_ginfo->statics_not_written =
507 copy_static_var_set (ginfo->statics_not_written);
510 /* Called when node is removed. */
512 static void
513 remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
515 ipa_reference_optimization_summary_t ginfo;
516 ginfo = get_reference_optimization_summary (node);
517 if (ginfo)
519 if (ginfo->statics_not_read
520 && ginfo->statics_not_read != all_module_statics)
521 BITMAP_FREE (ginfo->statics_not_read);
523 if (ginfo->statics_not_written
524 && ginfo->statics_not_written != all_module_statics)
525 BITMAP_FREE (ginfo->statics_not_written);
526 free (ginfo);
527 set_reference_optimization_summary (node, NULL);
531 /* Analyze each function in the cgraph to see which global or statics
532 are read or written. */
534 static void
535 generate_summary (void)
537 struct cgraph_node *node;
538 unsigned int index;
539 bitmap_iterator bi;
541 ipa_init ();
543 /* Process all of the functions next. */
544 FOR_EACH_DEFINED_FUNCTION (node)
545 analyze_function (node);
547 if (dump_file)
548 EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi)
550 fprintf (dump_file, "\nPromotable global:%s (uid=%u)\n",
551 get_static_name (index), index);
554 if (dump_file)
555 FOR_EACH_DEFINED_FUNCTION (node)
556 if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
558 ipa_reference_local_vars_info_t l;
559 unsigned int index;
560 bitmap_iterator bi;
562 l = &get_reference_vars_info (node)->local;
563 fprintf (dump_file,
564 "\nFunction name:%s/%i:",
565 cgraph_node_asm_name (node), node->order);
566 fprintf (dump_file, "\n locals read: ");
567 if (l->statics_read)
568 EXECUTE_IF_SET_IN_BITMAP (l->statics_read,
569 0, index, bi)
571 fprintf (dump_file, "%s ",
572 get_static_name (index));
574 fprintf (dump_file, "\n locals written: ");
575 if (l->statics_written)
576 EXECUTE_IF_SET_IN_BITMAP (l->statics_written,
577 0, index, bi)
579 fprintf (dump_file, "%s ", get_static_name (index));
584 /* Set READ_ALL/WRITE_ALL based on decl flags of NODE. */
586 static void
587 read_write_all_from_decl (struct cgraph_node *node,
588 bool &read_all, bool &write_all)
590 tree decl = node->decl;
591 int flags = flags_from_decl_or_type (decl);
592 if ((flags & ECF_LEAF)
593 && cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
595 else if (flags & ECF_CONST)
597 else if ((flags & ECF_PURE)
598 || cgraph_node_cannot_return (node))
600 read_all = true;
601 if (dump_file && (dump_flags & TDF_DETAILS))
602 fprintf (dump_file, " %s/%i -> read all\n",
603 cgraph_node_asm_name (node), node->order);
605 else
607 /* TODO: To be able to produce sane results, we should also handle
608 common builtins, in particular throw. */
609 read_all = true;
610 write_all = true;
611 if (dump_file && (dump_flags & TDF_DETAILS))
612 fprintf (dump_file, " %s/%i -> read all, write all\n",
613 cgraph_node_asm_name (node), node->order);
617 /* Set READ_ALL/WRITE_ALL based on decl flags of NODE or any member
618 in the cycle of NODE. */
620 static void
621 get_read_write_all_from_node (struct cgraph_node *node,
622 bool &read_all, bool &write_all)
624 struct cgraph_edge *e, *ie;
626 /* When function is overwritable, we can not assume anything. */
627 if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
628 read_write_all_from_decl (node, read_all, write_all);
630 for (e = node->callees;
631 e && !(read_all && write_all);
632 e = e->next_callee)
634 enum availability avail;
635 struct cgraph_node *callee = cgraph_function_node (e->callee, &avail);
636 gcc_checking_assert (callee);
637 if (avail <= AVAIL_OVERWRITABLE)
638 read_write_all_from_decl (callee, read_all, write_all);
641 for (ie = node->indirect_calls;
642 ie && !(read_all && write_all);
643 ie = ie->next_callee)
644 if (!(ie->indirect_info->ecf_flags & ECF_CONST))
646 read_all = true;
647 if (dump_file && (dump_flags & TDF_DETAILS))
648 fprintf (dump_file, " indirect call -> read all\n");
649 if (!cgraph_edge_cannot_lead_to_return (ie)
650 && !(ie->indirect_info->ecf_flags & ECF_PURE))
652 if (dump_file && (dump_flags & TDF_DETAILS))
653 fprintf (dump_file, " indirect call -> write all\n");
654 write_all = true;
659 /* Produce the global information by preforming a transitive closure
660 on the local information that was produced by ipa_analyze_function. */
662 static unsigned int
663 propagate (void)
665 struct cgraph_node *node;
666 struct varpool_node *vnode;
667 struct cgraph_node **order =
668 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
669 int order_pos;
670 int i;
672 if (dump_file)
673 dump_cgraph (dump_file);
675 ipa_discover_readonly_nonaddressable_vars ();
676 generate_summary ();
678 /* Now we know what vars are really statics; prune out those that aren't. */
679 FOR_EACH_VARIABLE (vnode)
680 if (vnode->externally_visible
681 || TREE_ADDRESSABLE (vnode->decl)
682 || TREE_READONLY (vnode->decl)
683 || !is_proper_for_analysis (vnode->decl)
684 || !vnode->definition)
685 bitmap_clear_bit (all_module_statics, DECL_UID (vnode->decl));
687 /* Forget info we collected "just for fun" on variables that turned out to be
688 non-local. */
689 FOR_EACH_DEFINED_FUNCTION (node)
691 ipa_reference_local_vars_info_t node_l;
692 node_l = &get_reference_vars_info (node)->local;
693 intersect_static_var_sets (node_l->statics_read, all_module_statics);
694 intersect_static_var_sets (node_l->statics_written, all_module_statics);
697 /* Propagate the local information through the call graph to produce
698 the global information. All the nodes within a cycle will have
699 the same info so we collapse cycles first. Then we can do the
700 propagation in one pass from the leaves to the roots. */
701 order_pos = ipa_reduced_postorder (order, true, true, NULL);
702 if (dump_file)
703 ipa_print_order (dump_file, "reduced", order, order_pos);
705 for (i = 0; i < order_pos; i++ )
707 unsigned x;
708 struct cgraph_node *w;
709 ipa_reference_vars_info_t node_info;
710 ipa_reference_global_vars_info_t node_g;
711 ipa_reference_local_vars_info_t node_l;
712 bool read_all = false;
713 bool write_all = false;
715 node = order[i];
716 if (node->alias)
717 continue;
719 node_info = get_reference_vars_info (node);
720 gcc_assert (node_info);
721 node_l = &node_info->local;
722 node_g = &node_info->global;
724 if (dump_file && (dump_flags & TDF_DETAILS))
725 fprintf (dump_file, "Starting cycle with %s/%i\n",
726 cgraph_node_asm_name (node), node->order);
728 vec<cgraph_node_ptr> cycle_nodes = ipa_get_nodes_in_cycle (node);
730 /* If any node in a cycle is read_all or write_all, they all are. */
731 FOR_EACH_VEC_ELT (cycle_nodes, x, w)
733 if (dump_file && (dump_flags & TDF_DETAILS))
734 fprintf (dump_file, " Visiting %s/%i\n",
735 cgraph_node_asm_name (w), w->order);
736 get_read_write_all_from_node (w, read_all, write_all);
737 if (read_all && write_all)
738 break;
741 /* Initialized the bitmaps global sets for the reduced node. */
742 if (read_all)
743 node_g->statics_read = all_module_statics;
744 else
745 node_g->statics_read = copy_static_var_set (node_l->statics_read);
746 if (write_all)
747 node_g->statics_written = all_module_statics;
748 else
749 node_g->statics_written = copy_static_var_set (node_l->statics_written);
751 /* Merge the sets of this cycle with all sets of callees reached
752 from this cycle. */
753 FOR_EACH_VEC_ELT (cycle_nodes, x, w)
755 if (read_all && write_all)
756 break;
758 if (w != node)
760 ipa_reference_vars_info_t w_ri = get_reference_vars_info (w);
761 ipa_reference_local_vars_info_t w_l = &w_ri->local;
762 int flags = flags_from_decl_or_type (w->decl);
764 if (!(flags & ECF_CONST))
765 read_all = union_static_var_sets (node_g->statics_read,
766 w_l->statics_read);
767 if (!(flags & ECF_PURE)
768 && !cgraph_node_cannot_return (w))
769 write_all = union_static_var_sets (node_g->statics_written,
770 w_l->statics_written);
773 propagate_bits (node_g, w);
776 /* All nodes within a cycle have the same global info bitmaps. */
777 FOR_EACH_VEC_ELT (cycle_nodes, x, w)
779 ipa_reference_vars_info_t w_ri = get_reference_vars_info (w);
780 w_ri->global = *node_g;
783 cycle_nodes.release ();
786 if (dump_file)
788 for (i = 0; i < order_pos; i++)
790 unsigned x;
791 struct cgraph_node *w;
793 node = order[i];
794 if (node->alias)
795 continue;
797 fprintf (dump_file,
798 "\nFunction name:%s/%i:",
799 cgraph_node_asm_name (node), node->order);
801 ipa_reference_vars_info_t node_info = get_reference_vars_info (node);
802 ipa_reference_global_vars_info_t node_g = &node_info->global;
804 vec<cgraph_node_ptr> cycle_nodes = ipa_get_nodes_in_cycle (node);
805 FOR_EACH_VEC_ELT (cycle_nodes, x, w)
807 ipa_reference_vars_info_t w_ri = get_reference_vars_info (w);
808 ipa_reference_local_vars_info_t w_l = &w_ri->local;
809 if (w != node)
810 fprintf (dump_file, "\n next cycle: %s/%i ",
811 cgraph_node_asm_name (w), w->order);
812 fprintf (dump_file, "\n locals read: ");
813 dump_static_vars_set_to_file (dump_file, w_l->statics_read);
814 fprintf (dump_file, "\n locals written: ");
815 dump_static_vars_set_to_file (dump_file, w_l->statics_written);
817 cycle_nodes.release ();
819 fprintf (dump_file, "\n globals read: ");
820 dump_static_vars_set_to_file (dump_file, node_g->statics_read);
821 fprintf (dump_file, "\n globals written: ");
822 dump_static_vars_set_to_file (dump_file, node_g->statics_written);
823 fprintf (dump_file, "\n");
827 /* Cleanup. */
828 FOR_EACH_DEFINED_FUNCTION (node)
830 ipa_reference_vars_info_t node_info;
831 ipa_reference_global_vars_info_t node_g;
832 ipa_reference_optimization_summary_t opt;
834 node_info = get_reference_vars_info (node);
835 if (!node->alias
836 && (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE
837 || (flags_from_decl_or_type (node->decl) & ECF_LEAF)))
839 node_g = &node_info->global;
841 opt = XCNEW (struct ipa_reference_optimization_summary_d);
842 set_reference_optimization_summary (node, opt);
844 /* Create the complimentary sets. */
846 if (bitmap_empty_p (node_g->statics_read))
847 opt->statics_not_read = all_module_statics;
848 else
850 opt->statics_not_read
851 = BITMAP_ALLOC (&optimization_summary_obstack);
852 if (node_g->statics_read != all_module_statics)
853 bitmap_and_compl (opt->statics_not_read,
854 all_module_statics,
855 node_g->statics_read);
858 if (bitmap_empty_p (node_g->statics_written))
859 opt->statics_not_written = all_module_statics;
860 else
862 opt->statics_not_written
863 = BITMAP_ALLOC (&optimization_summary_obstack);
864 if (node_g->statics_written != all_module_statics)
865 bitmap_and_compl (opt->statics_not_written,
866 all_module_statics,
867 node_g->statics_written);
870 free (node_info);
873 ipa_free_postorder_info ();
874 free (order);
876 bitmap_obstack_release (&local_info_obstack);
877 ipa_reference_vars_vector.release ();
878 if (dump_file)
879 splay_tree_delete (reference_vars_to_consider);
880 reference_vars_to_consider = NULL;
881 return 0;
884 /* Return true if we need to write summary of NODE. */
886 static bool
887 write_node_summary_p (struct cgraph_node *node,
888 lto_symtab_encoder_t encoder,
889 bitmap ltrans_statics)
891 ipa_reference_optimization_summary_t info;
893 /* See if we have (non-empty) info. */
894 if (!node->definition || node->global.inlined_to)
895 return false;
896 info = get_reference_optimization_summary (node);
897 if (!info || (bitmap_empty_p (info->statics_not_read)
898 && bitmap_empty_p (info->statics_not_written)))
899 return false;
901 /* See if we want to encode it.
902 Encode also referenced functions since constant folding might turn it into
903 a direct call.
905 In future we might also want to include summaries of functions references
906 by initializers of constant variables references in current unit. */
907 if (!reachable_from_this_partition_p (node, encoder)
908 && !referenced_from_this_partition_p (&node->ref_list, encoder))
909 return false;
911 /* See if the info has non-empty intersections with vars we want to encode. */
912 if (!bitmap_intersect_p (info->statics_not_read, ltrans_statics)
913 && !bitmap_intersect_p (info->statics_not_written, ltrans_statics))
914 return false;
915 return true;
918 /* Stream out BITS&LTRANS_STATICS as list of decls to OB.
919 LTRANS_STATICS_BITCOUNT specify number of bits in LTRANS_STATICS
920 or -1. When it is positive, just output -1 when
921 BITS&LTRANS_STATICS == BITS&LTRANS_STATICS. */
923 static void
924 stream_out_bitmap (struct lto_simple_output_block *ob,
925 bitmap bits, bitmap ltrans_statics,
926 int ltrans_statics_bitcount)
928 int count = 0;
929 unsigned int index;
930 bitmap_iterator bi;
931 if (bits == all_module_statics)
933 streamer_write_hwi_stream (ob->main_stream, -1);
934 return;
936 EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi)
937 count ++;
938 if (count == ltrans_statics_bitcount)
940 streamer_write_hwi_stream (ob->main_stream, -1);
941 return;
943 streamer_write_hwi_stream (ob->main_stream, count);
944 if (!count)
945 return;
946 EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi)
948 tree decl = (tree)splay_tree_lookup (reference_vars_to_consider, index)->value;
949 lto_output_var_decl_index (ob->decl_state, ob->main_stream, decl);
953 /* Serialize the ipa info for lto. */
955 static void
956 ipa_reference_write_optimization_summary (void)
958 struct lto_simple_output_block *ob
959 = lto_create_simple_output_block (LTO_section_ipa_reference);
960 unsigned int count = 0;
961 int ltrans_statics_bitcount = 0;
962 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
963 bitmap ltrans_statics = BITMAP_ALLOC (NULL);
964 int i;
966 reference_vars_to_consider = splay_tree_new (splay_tree_compare_ints, 0, 0);
968 /* See what variables we are interested in. */
969 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
971 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
972 varpool_node *vnode = dyn_cast <varpool_node> (snode);
973 if (vnode
974 && bitmap_bit_p (all_module_statics, DECL_UID (vnode->decl))
975 && referenced_from_this_partition_p (&vnode->ref_list, encoder))
977 tree decl = vnode->decl;
978 bitmap_set_bit (ltrans_statics, DECL_UID (decl));
979 splay_tree_insert (reference_vars_to_consider,
980 DECL_UID (decl), (splay_tree_value)decl);
981 ltrans_statics_bitcount ++;
986 if (ltrans_statics_bitcount)
987 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
989 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
990 cgraph_node *cnode = dyn_cast <cgraph_node> (snode);
991 if (cnode && write_node_summary_p (cnode, encoder, ltrans_statics))
992 count++;
995 streamer_write_uhwi_stream (ob->main_stream, count);
996 if (count)
997 stream_out_bitmap (ob, ltrans_statics, ltrans_statics,
998 -1);
1000 /* Process all of the functions. */
1001 if (ltrans_statics_bitcount)
1002 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
1004 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
1005 cgraph_node *cnode = dyn_cast <cgraph_node> (snode);
1006 if (cnode && write_node_summary_p (cnode, encoder, ltrans_statics))
1008 ipa_reference_optimization_summary_t info;
1009 int node_ref;
1011 info = get_reference_optimization_summary (cnode);
1012 node_ref = lto_symtab_encoder_encode (encoder, snode);
1013 streamer_write_uhwi_stream (ob->main_stream, node_ref);
1015 stream_out_bitmap (ob, info->statics_not_read, ltrans_statics,
1016 ltrans_statics_bitcount);
1017 stream_out_bitmap (ob, info->statics_not_written, ltrans_statics,
1018 ltrans_statics_bitcount);
1021 BITMAP_FREE (ltrans_statics);
1022 lto_destroy_simple_output_block (ob);
1023 splay_tree_delete (reference_vars_to_consider);
1026 /* Deserialize the ipa info for lto. */
1028 static void
1029 ipa_reference_read_optimization_summary (void)
1031 struct lto_file_decl_data ** file_data_vec
1032 = lto_get_file_decl_data ();
1033 struct lto_file_decl_data * file_data;
1034 unsigned int j = 0;
1035 bitmap_obstack_initialize (&optimization_summary_obstack);
1037 node_removal_hook_holder =
1038 cgraph_add_node_removal_hook (&remove_node_data, NULL);
1039 node_duplication_hook_holder =
1040 cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
1041 all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack);
1043 while ((file_data = file_data_vec[j++]))
1045 const char *data;
1046 size_t len;
1047 struct lto_input_block *ib
1048 = lto_create_simple_input_block (file_data,
1049 LTO_section_ipa_reference,
1050 &data, &len);
1051 if (ib)
1053 unsigned int i;
1054 unsigned int f_count = streamer_read_uhwi (ib);
1055 int b_count;
1056 if (!f_count)
1057 continue;
1058 b_count = streamer_read_hwi (ib);
1059 if (dump_file)
1060 fprintf (dump_file, "all module statics:");
1061 for (i = 0; i < (unsigned int)b_count; i++)
1063 unsigned int var_index = streamer_read_uhwi (ib);
1064 tree v_decl = lto_file_decl_data_get_var_decl (file_data,
1065 var_index);
1066 bitmap_set_bit (all_module_statics, DECL_UID (v_decl));
1067 if (dump_file)
1068 fprintf (dump_file, " %s", fndecl_name (v_decl));
1071 for (i = 0; i < f_count; i++)
1073 unsigned int j, index;
1074 struct cgraph_node *node;
1075 ipa_reference_optimization_summary_t info;
1076 int v_count;
1077 lto_symtab_encoder_t encoder;
1079 index = streamer_read_uhwi (ib);
1080 encoder = file_data->symtab_node_encoder;
1081 node = cgraph (lto_symtab_encoder_deref (encoder, index));
1082 info = XCNEW (struct ipa_reference_optimization_summary_d);
1083 set_reference_optimization_summary (node, info);
1084 info->statics_not_read = BITMAP_ALLOC (&optimization_summary_obstack);
1085 info->statics_not_written = BITMAP_ALLOC (&optimization_summary_obstack);
1086 if (dump_file)
1087 fprintf (dump_file,
1088 "\nFunction name:%s/%i:\n static not read:",
1089 cgraph_node_asm_name (node), node->order);
1091 /* Set the statics not read. */
1092 v_count = streamer_read_hwi (ib);
1093 if (v_count == -1)
1095 info->statics_not_read = all_module_statics;
1096 if (dump_file)
1097 fprintf (dump_file, " all module statics");
1099 else
1100 for (j = 0; j < (unsigned int)v_count; j++)
1102 unsigned int var_index = streamer_read_uhwi (ib);
1103 tree v_decl = lto_file_decl_data_get_var_decl (file_data,
1104 var_index);
1105 bitmap_set_bit (info->statics_not_read, DECL_UID (v_decl));
1106 if (dump_file)
1107 fprintf (dump_file, " %s", fndecl_name (v_decl));
1110 if (dump_file)
1111 fprintf (dump_file,
1112 "\n static not written:");
1113 /* Set the statics not written. */
1114 v_count = streamer_read_hwi (ib);
1115 if (v_count == -1)
1117 info->statics_not_written = all_module_statics;
1118 if (dump_file)
1119 fprintf (dump_file, " all module statics");
1121 else
1122 for (j = 0; j < (unsigned int)v_count; j++)
1124 unsigned int var_index = streamer_read_uhwi (ib);
1125 tree v_decl = lto_file_decl_data_get_var_decl (file_data,
1126 var_index);
1127 bitmap_set_bit (info->statics_not_written, DECL_UID (v_decl));
1128 if (dump_file)
1129 fprintf (dump_file, " %s", fndecl_name (v_decl));
1131 if (dump_file)
1132 fprintf (dump_file, "\n");
1135 lto_destroy_simple_input_block (file_data,
1136 LTO_section_ipa_reference,
1137 ib, data, len);
1139 else
1140 /* Fatal error here. We do not want to support compiling ltrans units with
1141 different version of compiler or different flags than the WPA unit, so
1142 this should never happen. */
1143 fatal_error ("ipa reference summary is missing in ltrans unit");
1147 static bool
1148 gate_reference (void)
1150 return (flag_ipa_reference
1151 /* Don't bother doing anything if the program has errors. */
1152 && !seen_error ());
1155 namespace {
1157 const pass_data pass_data_ipa_reference =
1159 IPA_PASS, /* type */
1160 "static-var", /* name */
1161 OPTGROUP_NONE, /* optinfo_flags */
1162 true, /* has_gate */
1163 true, /* has_execute */
1164 TV_IPA_REFERENCE, /* tv_id */
1165 0, /* properties_required */
1166 0, /* properties_provided */
1167 0, /* properties_destroyed */
1168 0, /* todo_flags_start */
1169 0, /* todo_flags_finish */
1172 class pass_ipa_reference : public ipa_opt_pass_d
1174 public:
1175 pass_ipa_reference (gcc::context *ctxt)
1176 : ipa_opt_pass_d (pass_data_ipa_reference, ctxt,
1177 NULL, /* generate_summary */
1178 NULL, /* write_summary */
1179 NULL, /* read_summary */
1180 ipa_reference_write_optimization_summary, /*
1181 write_optimization_summary */
1182 ipa_reference_read_optimization_summary, /*
1183 read_optimization_summary */
1184 NULL, /* stmt_fixup */
1185 0, /* function_transform_todo_flags_start */
1186 NULL, /* function_transform */
1187 NULL) /* variable_transform */
1190 /* opt_pass methods: */
1191 bool gate () { return gate_reference (); }
1192 unsigned int execute () { return propagate (); }
1194 }; // class pass_ipa_reference
1196 } // anon namespace
1198 ipa_opt_pass_d *
1199 make_pass_ipa_reference (gcc::context *ctxt)
1201 return new pass_ipa_reference (ctxt);