1/* Callgraph based analysis of static variables.
2 Copyright (C) 2004-2023 Free Software Foundation, Inc.
3 Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21/* This file gathers information about how variables whose scope is
22 confined to the compilation unit are used.
23
24 The transitive call site specific clobber effects are computed
25 for the variables whose scope is contained within this compilation
26 unit.
27
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. */
38
39#include "config.h"
40#include "system.h"
41#include "coretypes.h"
42#include "backend.h"
43#include "tree.h"
44#include "gimple.h"
45#include "tree-pass.h"
46#include "cgraph.h"
47#include "data-streamer.h"
48#include "calls.h"
49#include "ipa-utils.h"
50#include "ipa-reference.h"
51#include "alloc-pool.h"
52#include "symbol-summary.h"
53
54/* The static variables defined within the compilation unit that are
55 loaded or stored directly by function that owns this structure. */
56
57struct ipa_reference_local_vars_info_d
58{
59 bitmap statics_read;
60 bitmap statics_written;
61};
62
63/* Statics that are read and written by some set of functions. The
64 local ones are based on the loads and stores local to the function.
65 The global ones are based on the local info as well as the
66 transitive closure of the functions that are called. */
67
68struct ipa_reference_global_vars_info_d
69{
70 bitmap statics_read;
71 bitmap statics_written;
72};
73
74/* Information we save about every function after ipa-reference is completed. */
75
76struct ipa_reference_optimization_summary_d
77{
78 bitmap statics_read;
79 bitmap statics_written;
80};
81
82typedef ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t;
83typedef ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t;
84typedef ipa_reference_optimization_summary_d *
85 ipa_reference_optimization_summary_t;
86
87struct ipa_reference_vars_info_d
88{
89 struct ipa_reference_local_vars_info_d local;
90 struct ipa_reference_global_vars_info_d global;
91};
92
93typedef struct ipa_reference_vars_info_d *ipa_reference_vars_info_t;
94
95/* This map contains all of the static variables that are
96 being considered by the compilation level alias analysis. */
97typedef hash_map<tree, int> reference_vars_map_t;
98static reference_vars_map_t *ipa_reference_vars_map;
99static int ipa_reference_vars_uids;
100static vec<tree> *reference_vars_to_consider;
101varpool_node_hook_list *varpool_node_hooks;
102
103/* Set of all interesting module statics. A bit is set for every module
104 static we are considering. This is added to the local info when asm
105 code is found that clobbers all memory. */
106static bitmap all_module_statics;
107/* Zero bitmap. */
108static bitmap no_module_statics;
109/* Set of all statics that should be ignored because they are touched by
110 -fno-ipa-reference code. */
111static bitmap ignore_module_statics;
112
113/* Obstack holding bitmaps of local analysis (live from analysis to
114 propagation) */
115static bitmap_obstack local_info_obstack;
116/* Obstack holding global analysis live forever. */
117static bitmap_obstack optimization_summary_obstack;
118
119class ipa_ref_var_info_summary_t: public fast_function_summary
120 <ipa_reference_vars_info_d *, va_heap>
121{
122public:
123 ipa_ref_var_info_summary_t (symbol_table *symtab):
124 fast_function_summary <ipa_reference_vars_info_d *, va_heap> (symtab) {}
125};
126
127static ipa_ref_var_info_summary_t *ipa_ref_var_info_summaries = NULL;
128
129class ipa_ref_opt_summary_t: public fast_function_summary
130 <ipa_reference_optimization_summary_d *, va_heap>
131{
132public:
133 ipa_ref_opt_summary_t (symbol_table *symtab):
134 fast_function_summary <ipa_reference_optimization_summary_d *, va_heap> (symtab) {}
135
136 void remove (cgraph_node *src_node,
137 ipa_reference_optimization_summary_d *data) final override;
138 void duplicate (cgraph_node *src_node, cgraph_node *dst_node,
139 ipa_reference_optimization_summary_d *src_data,
140 ipa_reference_optimization_summary_d *dst_data) final override;
141};
142
143static ipa_ref_opt_summary_t *ipa_ref_opt_sum_summaries = NULL;
144
145/* Return ID used by ipa-reference bitmaps. -1 if failed. */
146int
147ipa_reference_var_uid (tree t)
148{
149 if (!ipa_reference_vars_map)
150 return -1;
151 int *id = ipa_reference_vars_map->get
152 (k: symtab_node::get (decl: t)->ultimate_alias_target (NULL)->decl);
153 if (!id)
154 return -1;
155 return *id;
156}
157
158/* Return ID used by ipa-reference bitmaps. Create new entry if
159 T is not in map. Set EXISTED accordinly */
160int
161ipa_reference_var_get_or_insert_uid (tree t, bool *existed)
162{
163 int &id = ipa_reference_vars_map->get_or_insert
164 (k: symtab_node::get (decl: t)->ultimate_alias_target (NULL)->decl, existed);
165 if (!*existed)
166 id = ipa_reference_vars_uids++;
167 return id;
168}
169
170/* Return the ipa_reference_vars structure starting from the cgraph NODE. */
171static inline ipa_reference_vars_info_t
172get_reference_vars_info (struct cgraph_node *node)
173{
174 if (ipa_ref_var_info_summaries == NULL)
175 return NULL;
176
177 ipa_reference_vars_info_t v = ipa_ref_var_info_summaries->get (node);
178 return v == NULL ? NULL : v;
179}
180
181/* Return the ipa_reference_vars structure starting from the cgraph NODE. */
182static inline ipa_reference_optimization_summary_t
183get_reference_optimization_summary (struct cgraph_node *node)
184{
185 if (ipa_ref_opt_sum_summaries == NULL)
186 return NULL;
187
188 ipa_reference_optimization_summary_t v
189 = ipa_ref_opt_sum_summaries->get (node);
190
191 return v == NULL ? NULL : v;
192}
193
194/* Return a bitmap indexed by ipa_reference_var_uid for the static variables
195 that are *not* read during the execution of the function FN. Returns
196 NULL if no data is available. */
197
198bitmap
199ipa_reference_get_read_global (struct cgraph_node *fn)
200{
201 if (!opt_for_fn (current_function_decl, flag_ipa_reference))
202 return NULL;
203
204 enum availability avail;
205 struct cgraph_node *fn2 = fn->function_symbol (avail: &avail);
206 ipa_reference_optimization_summary_t info =
207 get_reference_optimization_summary (node: fn2);
208
209 if (info
210 && (avail >= AVAIL_AVAILABLE
211 || (avail == AVAIL_INTERPOSABLE
212 && flags_from_decl_or_type (fn->decl) & ECF_LEAF))
213 && opt_for_fn (fn2->decl, flag_ipa_reference))
214 return info->statics_read;
215 else if (avail == AVAIL_NOT_AVAILABLE
216 && flags_from_decl_or_type (fn->decl) & ECF_LEAF)
217 return no_module_statics;
218 else
219 return NULL;
220}
221
222/* Return a bitmap indexed by ipa_reference_var_uid for the static variables
223 that are *not* written during the execution of the function FN. Note
224 that variables written may or may not be read during the function
225 call. Returns NULL if no data is available. */
226
227bitmap
228ipa_reference_get_written_global (struct cgraph_node *fn)
229{
230 if (!opt_for_fn (current_function_decl, flag_ipa_reference))
231 return NULL;
232
233 enum availability avail;
234 struct cgraph_node *fn2 = fn->function_symbol (avail: &avail);
235 ipa_reference_optimization_summary_t info =
236 get_reference_optimization_summary (node: fn2);
237
238 if (info
239 && (avail >= AVAIL_AVAILABLE
240 || (avail == AVAIL_INTERPOSABLE
241 && flags_from_decl_or_type (fn->decl) & ECF_LEAF))
242 && opt_for_fn (fn2->decl, flag_ipa_reference))
243 return info->statics_written;
244 else if (avail == AVAIL_NOT_AVAILABLE
245 && flags_from_decl_or_type (fn->decl) & ECF_LEAF)
246 return no_module_statics;
247 else
248 return NULL;
249}
250
251
252/* Hepler for is_proper_for_analysis. */
253static bool
254is_improper (symtab_node *n, void *v ATTRIBUTE_UNUSED)
255{
256 tree t = n->decl;
257 /* If the variable has the "used" attribute, treat it as if it had a
258 been touched by the devil. */
259 if (DECL_PRESERVE_P (t))
260 return true;
261
262 /* Do not want to do anything with volatile except mark any
263 function that uses one to be not const or pure. */
264 if (TREE_THIS_VOLATILE (t))
265 return true;
266
267 /* We do not need to analyze readonly vars, we already know they do not
268 alias. */
269 if (TREE_READONLY (t))
270 return true;
271
272 /* We cannot track variables with address taken. */
273 if (TREE_ADDRESSABLE (t))
274 return true;
275
276 /* TODO: We could track public variables that are not addressable, but
277 currently frontends don't give us those. */
278 if (TREE_PUBLIC (t))
279 return true;
280
281 return false;
282}
283
284/* Return true if the variable T is the right kind of static variable to
285 perform compilation unit scope escape analysis. */
286
287static inline bool
288is_proper_for_analysis (tree t)
289{
290 int id = ipa_reference_var_uid (t);
291
292 if (id != -1 && bitmap_bit_p (ignore_module_statics, id))
293 return false;
294
295 if (symtab_node::get (decl: t)
296 ->call_for_symbol_and_aliases (callback: is_improper, NULL, include_overwritable: true))
297 return false;
298
299 return true;
300}
301
302/* Lookup the tree node for the static variable that has UID and
303 convert the name to a string for debugging. */
304
305static const char *
306get_static_name (int index)
307{
308 return fndecl_name ((*reference_vars_to_consider)[index]);
309}
310
311/* Dump a set of static vars to FILE. */
312static void
313dump_static_vars_set_to_file (FILE *f, bitmap set)
314{
315 unsigned int index;
316 bitmap_iterator bi;
317 if (set == NULL)
318 return;
319 else if (set == all_module_statics)
320 fprintf (stream: f, format: "ALL");
321 else if (set == no_module_statics)
322 fprintf (stream: f, format: "NO");
323 else
324 EXECUTE_IF_SET_IN_BITMAP (set, 0, index, bi)
325 {
326 fprintf (stream: f, format: "%s ", get_static_name (index));
327 }
328}
329
330/* Compute X |= Y, taking into account the possibility that
331 either X or Y is already the maximum set.
332 Return true if X is the maximum set after taking the union with Y. */
333
334static bool
335union_static_var_sets (bitmap &x, bitmap y)
336{
337 if (x != all_module_statics)
338 {
339 if (y == all_module_statics)
340 {
341 BITMAP_FREE (x);
342 x = all_module_statics;
343 }
344 else if (bitmap_ior_into (x, y))
345 {
346 /* The union may have reduced X to the maximum set.
347 In that case, we want to make that visible explicitly.
348 Even though bitmap_equal_p can be very expensive, it
349 turns out to be an overall win to check this here for
350 an LTO bootstrap of GCC itself. Liberally extrapoliate
351 that result to be applicable to all cases. */
352 if (bitmap_equal_p (x, all_module_statics))
353 {
354 BITMAP_FREE (x);
355 x = all_module_statics;
356 }
357 }
358 }
359 return x == all_module_statics;
360}
361
362/* Return a copy of SET on the bitmap obstack containing SET.
363 But if SET is NULL or the maximum set, return that instead. */
364
365static bitmap
366copy_static_var_set (bitmap set, bool for_propagation)
367{
368 if (set == NULL || set == all_module_statics)
369 return set;
370 if (!for_propagation && set == no_module_statics)
371 return set;
372 bitmap_obstack *o = set->obstack;
373 gcc_checking_assert (o);
374 bitmap copy = BITMAP_ALLOC (obstack: o);
375 bitmap_copy (copy, set);
376 return copy;
377}
378
379/* Compute the union all of the statics read and written by every callee of X
380 into X_GLOBAL->statics_read and X_GLOBAL->statics_written. X_GLOBAL is
381 actually the set representing the cycle containing X. If the read and
382 written sets of X_GLOBAL has been reduced to the maximum set, we don't
383 have to look at the remaining callees. */
384
385static void
386propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x)
387{
388 struct cgraph_edge *e;
389 bool read_all = x_global->statics_read == all_module_statics;
390 bool write_all = x_global->statics_written == all_module_statics;
391 for (e = x->callees;
392 e && !(read_all && write_all);
393 e = e->next_callee)
394 {
395 enum availability avail;
396 struct cgraph_node *y = e->callee->function_symbol (avail: &avail);
397 if (!y)
398 continue;
399
400 /* Only look into nodes we can propagate something. */
401 int flags = flags_from_decl_or_type (y->decl);
402 if (opt_for_fn (y->decl, flag_ipa_reference)
403 && (avail > AVAIL_INTERPOSABLE
404 || (avail == AVAIL_INTERPOSABLE && (flags & ECF_LEAF))))
405 {
406 if (get_reference_vars_info (node: y))
407 {
408 ipa_reference_vars_info_t y_info = get_reference_vars_info (node: y);
409 ipa_reference_global_vars_info_t y_global = &y_info->global;
410
411 /* Calls in the current cycle do not have their global set
412 computed yet (but everything else does because we're
413 visiting nodes in topological order). */
414 if (!y_global->statics_read)
415 continue;
416
417 /* If the function is const, it reads no memory even if it
418 seems so to local analysis. */
419 if (flags & ECF_CONST)
420 continue;
421
422 union_static_var_sets (x&: x_global->statics_read,
423 y: y_global->statics_read);
424
425 /* If the function is pure, it has no stores even if it
426 seems so to local analysis. If we cannot return from
427 the function, we can safely ignore the call. */
428 if ((flags & ECF_PURE)
429 || e->cannot_lead_to_return_p ())
430 continue;
431
432 union_static_var_sets (x&: x_global->statics_written,
433 y: y_global->statics_written);
434 }
435 else
436 gcc_unreachable ();
437 }
438 }
439}
440
441/* Delete NODE from map. */
442
443static void
444varpool_removal_hook (varpool_node *node, void *)
445{
446 ipa_reference_vars_map->remove (k: node->decl);
447}
448
449static bool ipa_init_p = false;
450
451/* The init routine for analyzing global static variable usage. See
452 comments at top for description. */
453static void
454ipa_init (void)
455{
456 if (ipa_init_p)
457 return;
458
459 ipa_init_p = true;
460
461 if (dump_file)
462 vec_alloc (v&: reference_vars_to_consider, nelems: 10);
463
464 if (ipa_ref_opt_sum_summaries != NULL)
465 {
466 delete ipa_ref_opt_sum_summaries;
467 ipa_ref_opt_sum_summaries = NULL;
468 delete ipa_reference_vars_map;
469 }
470 ipa_reference_vars_map = new reference_vars_map_t(257);
471 varpool_node_hooks
472 = symtab->add_varpool_removal_hook (hook: varpool_removal_hook, NULL);
473 ipa_reference_vars_uids = 0;
474
475 bitmap_obstack_initialize (&local_info_obstack);
476 bitmap_obstack_initialize (&optimization_summary_obstack);
477 all_module_statics = BITMAP_ALLOC (obstack: &optimization_summary_obstack);
478 no_module_statics = BITMAP_ALLOC (obstack: &optimization_summary_obstack);
479 ignore_module_statics = BITMAP_ALLOC (obstack: &optimization_summary_obstack);
480
481 if (ipa_ref_var_info_summaries == NULL)
482 ipa_ref_var_info_summaries = new ipa_ref_var_info_summary_t (symtab);
483}
484
485
486/* Set up the persistent info for FN. */
487
488static ipa_reference_local_vars_info_t
489init_function_info (struct cgraph_node *fn)
490{
491 ipa_reference_vars_info_t info
492 = ipa_ref_var_info_summaries->get_create (node: fn);
493
494 info->local.statics_read = BITMAP_ALLOC (obstack: &local_info_obstack);
495 info->local.statics_written = BITMAP_ALLOC (obstack: &local_info_obstack);
496 info->global.statics_read = NULL;
497
498 return &info->local;
499}
500
501
502/* This is the main routine for finding the reference patterns for
503 global variables within a function FN. */
504
505static void
506analyze_function (struct cgraph_node *fn)
507{
508 ipa_reference_local_vars_info_t local;
509 struct ipa_ref *ref = NULL;
510 int i;
511 tree var;
512
513 if (!opt_for_fn (fn->decl, flag_ipa_reference))
514 return;
515 local = init_function_info (fn);
516 for (i = 0; fn->iterate_reference (i, ref); i++)
517 {
518 int id;
519 bool existed;
520 if (!is_a <varpool_node *> (p: ref->referred))
521 continue;
522 var = ref->referred->decl;
523 if (!is_proper_for_analysis (t: var))
524 continue;
525 /* This is a variable we care about. Check if we have seen it
526 before, and if not add it the set of variables we care about. */
527 id = ipa_reference_var_get_or_insert_uid (t: var, existed: &existed);
528 if (!existed)
529 {
530 bitmap_set_bit (all_module_statics, id);
531 if (dump_file)
532 reference_vars_to_consider->safe_push (obj: var);
533 }
534 switch (ref->use)
535 {
536 case IPA_REF_LOAD:
537 bitmap_set_bit (local->statics_read, id);
538 break;
539 case IPA_REF_STORE:
540 if (ref->cannot_lead_to_return ())
541 break;
542 bitmap_set_bit (local->statics_written, id);
543 break;
544 case IPA_REF_ADDR:
545 break;
546 default:
547 gcc_unreachable ();
548 }
549 }
550
551 if (fn->cannot_return_p ())
552 bitmap_clear (local->statics_written);
553}
554
555
556/* Called when new clone is inserted to callgraph late. */
557
558void
559ipa_ref_opt_summary_t::duplicate (cgraph_node *, cgraph_node *,
560 ipa_reference_optimization_summary_d *ginfo,
561 ipa_reference_optimization_summary_d
562 *dst_ginfo)
563{
564 dst_ginfo->statics_read =
565 copy_static_var_set (set: ginfo->statics_read, for_propagation: false);
566 dst_ginfo->statics_written =
567 copy_static_var_set (set: ginfo->statics_written, for_propagation: false);
568}
569
570/* Called when node is removed. */
571
572void
573ipa_ref_opt_summary_t::remove (cgraph_node *,
574 ipa_reference_optimization_summary_d *ginfo)
575{
576 if (ginfo->statics_read
577 && ginfo->statics_read != all_module_statics
578 && ginfo->statics_read != no_module_statics)
579 BITMAP_FREE (ginfo->statics_read);
580
581 if (ginfo->statics_written
582 && ginfo->statics_written != all_module_statics
583 && ginfo->statics_written != no_module_statics)
584 BITMAP_FREE (ginfo->statics_written);
585}
586
587/* Analyze each function in the cgraph to see which global or statics
588 are read or written. */
589
590static void
591generate_summary (void)
592{
593 struct cgraph_node *node;
594 unsigned int index;
595 bitmap_iterator bi;
596
597 ipa_init ();
598
599 /* Process all of the functions next. */
600 FOR_EACH_DEFINED_FUNCTION (node)
601 if (!node->alias && !opt_for_fn (node->decl, flag_ipa_reference))
602 {
603 struct ipa_ref *ref = NULL;
604 int i;
605 tree var;
606 for (i = 0; node->iterate_reference (i, ref); i++)
607 {
608 if (!is_a <varpool_node *> (p: ref->referred))
609 continue;
610 var = ref->referred->decl;
611 if (!is_proper_for_analysis (t: var))
612 continue;
613 bitmap_set_bit (ignore_module_statics, ipa_reference_var_uid (t: var));
614 }
615 }
616 FOR_EACH_DEFINED_FUNCTION (node)
617 analyze_function (fn: node);
618
619 if (dump_file)
620 EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi)
621 {
622 fprintf (stream: dump_file, format: "\nPromotable global:%s (uid=%u)\n",
623 get_static_name (index), index);
624 }
625
626 if (dump_file)
627 FOR_EACH_DEFINED_FUNCTION (node)
628 if (node->get_availability () >= AVAIL_INTERPOSABLE
629 && opt_for_fn (node->decl, flag_ipa_reference))
630 {
631 ipa_reference_local_vars_info_t l;
632 unsigned int index;
633 bitmap_iterator bi;
634
635 l = &get_reference_vars_info (node)->local;
636 fprintf (stream: dump_file,
637 format: "\nFunction name:%s:", node->dump_name ());
638 fprintf (stream: dump_file, format: "\n locals read: ");
639 if (l->statics_read)
640 EXECUTE_IF_SET_IN_BITMAP (l->statics_read,
641 0, index, bi)
642 {
643 fprintf (stream: dump_file, format: "%s ",
644 get_static_name (index));
645 }
646 fprintf (stream: dump_file, format: "\n locals written: ");
647 if (l->statics_written)
648 EXECUTE_IF_SET_IN_BITMAP (l->statics_written,
649 0, index, bi)
650 {
651 fprintf (stream: dump_file, format: "%s ", get_static_name (index));
652 }
653 }
654}
655
656/* Set READ_ALL/WRITE_ALL based on decl flags of NODE. */
657
658static void
659read_write_all_from_decl (struct cgraph_node *node,
660 bool &read_all, bool &write_all)
661{
662 tree decl = node->decl;
663 int flags = flags_from_decl_or_type (decl);
664 if ((flags & ECF_LEAF)
665 && node->get_availability () < AVAIL_INTERPOSABLE)
666 ;
667 else if (flags & ECF_CONST)
668 ;
669 else if ((flags & ECF_PURE) || node->cannot_return_p ())
670 {
671 read_all = true;
672 if (dump_file && (dump_flags & TDF_DETAILS))
673 fprintf (stream: dump_file, format: " %s -> read all\n", node->dump_name ());
674 }
675 else
676 {
677 /* TODO: To be able to produce sane results, we should also handle
678 common builtins, in particular throw. */
679 read_all = true;
680 write_all = true;
681 if (dump_file && (dump_flags & TDF_DETAILS))
682 fprintf (stream: dump_file, format: " %s -> read all, write all\n",
683 node->dump_name ());
684 }
685}
686
687/* Set READ_ALL/WRITE_ALL based on decl flags of NODE or any member
688 in the cycle of NODE. */
689
690static void
691get_read_write_all_from_node (struct cgraph_node *node,
692 bool &read_all, bool &write_all)
693{
694 struct cgraph_edge *e, *ie;
695
696 /* When function is overwritable, we cannot assume anything. */
697 if (node->get_availability () <= AVAIL_INTERPOSABLE
698 || (node->analyzed && !opt_for_fn (node->decl, flag_ipa_reference)))
699 read_write_all_from_decl (node, read_all, write_all);
700
701 for (e = node->callees;
702 e && !(read_all && write_all);
703 e = e->next_callee)
704 {
705 enum availability avail;
706 struct cgraph_node *callee = e->callee->function_symbol (avail: &avail);
707 gcc_checking_assert (callee);
708 if (avail <= AVAIL_INTERPOSABLE
709 || (callee->analyzed && !opt_for_fn (callee->decl,
710 flag_ipa_reference)))
711 read_write_all_from_decl (node: callee, read_all, write_all);
712 }
713
714 for (ie = node->indirect_calls;
715 ie && !(read_all && write_all);
716 ie = ie->next_callee)
717 if (!(ie->indirect_info->ecf_flags & ECF_CONST))
718 {
719 read_all = true;
720 if (dump_file && (dump_flags & TDF_DETAILS))
721 fprintf (stream: dump_file, format: " indirect call -> read all\n");
722 if (!ie->cannot_lead_to_return_p ()
723 && !(ie->indirect_info->ecf_flags & ECF_PURE))
724 {
725 if (dump_file && (dump_flags & TDF_DETAILS))
726 fprintf (stream: dump_file, format: " indirect call -> write all\n");
727 write_all = true;
728 }
729 }
730}
731
732/* Skip edges from and to nodes without ipa_reference enabled.
733 Ignore not available symbols. This leave
734 them out of strongly connected components and makes them easy to skip in the
735 propagation loop bellow. */
736
737static bool
738ignore_edge_p (cgraph_edge *e)
739{
740 enum availability avail;
741 cgraph_node *ultimate_target
742 = e->callee->function_or_virtual_thunk_symbol (avail: &avail, ref: e->caller);
743
744 return (avail < AVAIL_INTERPOSABLE
745 || (avail == AVAIL_INTERPOSABLE
746 && !(flags_from_decl_or_type (e->callee->decl) & ECF_LEAF))
747 || !opt_for_fn (e->caller->decl, flag_ipa_reference)
748 || !opt_for_fn (ultimate_target->decl, flag_ipa_reference));
749}
750
751/* Produce the global information by preforming a transitive closure
752 on the local information that was produced by ipa_analyze_function. */
753
754static unsigned int
755propagate (void)
756{
757 struct cgraph_node *node;
758 struct cgraph_node **order =
759 XCNEWVEC (struct cgraph_node *, symtab->cgraph_count);
760 int order_pos;
761 int i;
762 bool remove_p;
763
764 if (dump_file)
765 cgraph_node::dump_cgraph (f: dump_file);
766
767 remove_p = ipa_discover_variable_flags ();
768 generate_summary ();
769
770 /* Propagate the local information through the call graph to produce
771 the global information. All the nodes within a cycle will have
772 the same info so we collapse cycles first. Then we can do the
773 propagation in one pass from the leaves to the roots. */
774 order_pos = ipa_reduced_postorder (order, true, ignore_edge: ignore_edge_p);
775 if (dump_file)
776 ipa_print_order (dump_file, "reduced", order, order_pos);
777
778 for (i = 0; i < order_pos; i++ )
779 {
780 unsigned x;
781 struct cgraph_node *w;
782 ipa_reference_vars_info_t node_info;
783 ipa_reference_global_vars_info_t node_g;
784 ipa_reference_local_vars_info_t node_l;
785 bool read_all = false;
786 bool write_all = false;
787
788 node = order[i];
789 if (node->alias || !opt_for_fn (node->decl, flag_ipa_reference))
790 continue;
791
792 node_info = get_reference_vars_info (node);
793 gcc_assert (node_info);
794 node_l = &node_info->local;
795 node_g = &node_info->global;
796
797 if (dump_file && (dump_flags & TDF_DETAILS))
798 fprintf (stream: dump_file, format: "Starting cycle with %s\n", node->dump_name ());
799
800 vec<cgraph_node *> cycle_nodes = ipa_get_nodes_in_cycle (node);
801
802 /* If any node in a cycle is read_all or write_all, they all are. */
803 FOR_EACH_VEC_ELT (cycle_nodes, x, w)
804 {
805 if (dump_file && (dump_flags & TDF_DETAILS))
806 fprintf (stream: dump_file, format: " Visiting %s\n", w->dump_asm_name ());
807 get_read_write_all_from_node (node: w, read_all, write_all);
808 if (read_all && write_all)
809 break;
810 }
811
812 /* Initialized the bitmaps global sets for the reduced node. */
813 if (read_all)
814 node_g->statics_read = all_module_statics;
815 else
816 node_g->statics_read = copy_static_var_set (set: node_l->statics_read, for_propagation: true);
817 if (write_all)
818 node_g->statics_written = all_module_statics;
819 else
820 node_g->statics_written
821 = copy_static_var_set (set: node_l->statics_written, for_propagation: true);
822
823 /* Merge the sets of this cycle with all sets of callees reached
824 from this cycle. */
825 FOR_EACH_VEC_ELT (cycle_nodes, x, w)
826 {
827 if (read_all && write_all)
828 break;
829
830 if (w != node)
831 {
832 ipa_reference_vars_info_t w_ri = get_reference_vars_info (node: w);
833 ipa_reference_local_vars_info_t w_l = &w_ri->local;
834 int flags = flags_from_decl_or_type (w->decl);
835
836 if (!(flags & ECF_CONST))
837 read_all = union_static_var_sets (x&: node_g->statics_read,
838 y: w_l->statics_read);
839 if (!(flags & ECF_PURE)
840 && !w->cannot_return_p ())
841 write_all = union_static_var_sets (x&: node_g->statics_written,
842 y: w_l->statics_written);
843 }
844
845 propagate_bits (x_global: node_g, x: w);
846 }
847
848 /* All nodes within a cycle have the same global info bitmaps. */
849 FOR_EACH_VEC_ELT (cycle_nodes, x, w)
850 {
851 ipa_reference_vars_info_t w_ri = get_reference_vars_info (node: w);
852 w_ri->global = *node_g;
853 }
854
855 cycle_nodes.release ();
856 }
857
858 if (dump_file)
859 {
860 for (i = 0; i < order_pos; i++)
861 {
862 unsigned x;
863 struct cgraph_node *w;
864
865 node = order[i];
866 if (node->alias || !opt_for_fn (node->decl, flag_ipa_reference))
867 continue;
868
869 fprintf (stream: dump_file, format: "\nFunction name:%s:", node->dump_asm_name ());
870
871 ipa_reference_vars_info_t node_info = get_reference_vars_info (node);
872 ipa_reference_global_vars_info_t node_g = &node_info->global;
873
874 vec<cgraph_node *> cycle_nodes = ipa_get_nodes_in_cycle (node);
875 FOR_EACH_VEC_ELT (cycle_nodes, x, w)
876 {
877 ipa_reference_vars_info_t w_ri = get_reference_vars_info (node: w);
878 ipa_reference_local_vars_info_t w_l = &w_ri->local;
879 if (w != node)
880 fprintf (stream: dump_file, format: "\n next cycle: %s ", w->dump_asm_name ());
881 fprintf (stream: dump_file, format: "\n locals read: ");
882 dump_static_vars_set_to_file (f: dump_file, set: w_l->statics_read);
883 fprintf (stream: dump_file, format: "\n locals written: ");
884 dump_static_vars_set_to_file (f: dump_file, set: w_l->statics_written);
885 }
886 cycle_nodes.release ();
887
888 fprintf (stream: dump_file, format: "\n globals read: ");
889 dump_static_vars_set_to_file (f: dump_file, set: node_g->statics_read);
890 fprintf (stream: dump_file, format: "\n globals written: ");
891 dump_static_vars_set_to_file (f: dump_file, set: node_g->statics_written);
892 fprintf (stream: dump_file, format: "\n");
893 }
894 }
895
896 if (ipa_ref_opt_sum_summaries == NULL)
897 {
898 ipa_ref_opt_sum_summaries = new ipa_ref_opt_summary_t (symtab);
899 ipa_ref_opt_sum_summaries->disable_insertion_hook ();
900 }
901
902 /* Cleanup. */
903 FOR_EACH_DEFINED_FUNCTION (node)
904 {
905 ipa_reference_vars_info_t node_info;
906 ipa_reference_global_vars_info_t node_g;
907
908 /* No need to produce summaries for inline clones. */
909 if (node->inlined_to)
910 continue;
911
912 node_info = get_reference_vars_info (node);
913 if (!node->alias && opt_for_fn (node->decl, flag_ipa_reference))
914 {
915 node_g = &node_info->global;
916 bool read_all =
917 (node_g->statics_read == all_module_statics
918 || bitmap_equal_p (node_g->statics_read, all_module_statics));
919 bool written_all =
920 (node_g->statics_written == all_module_statics
921 || bitmap_equal_p (node_g->statics_written,
922 all_module_statics));
923
924 /* There is no need to produce summary if we collected nothing
925 useful. */
926 if (read_all && written_all)
927 continue;
928
929 ipa_reference_optimization_summary_d *opt
930 = ipa_ref_opt_sum_summaries->get_create (node);
931
932 /* Create the complimentary sets. */
933
934 if (bitmap_empty_p (map: node_g->statics_read))
935 opt->statics_read = no_module_statics;
936 else if (read_all)
937 opt->statics_read = all_module_statics;
938 else
939 {
940 opt->statics_read
941 = BITMAP_ALLOC (obstack: &optimization_summary_obstack);
942 bitmap_copy (opt->statics_read, node_g->statics_read);
943 }
944
945 if (bitmap_empty_p (map: node_g->statics_written))
946 opt->statics_written = no_module_statics;
947 else if (written_all)
948 opt->statics_written = all_module_statics;
949 else
950 {
951 opt->statics_written
952 = BITMAP_ALLOC (obstack: &optimization_summary_obstack);
953 bitmap_copy (opt->statics_written, node_g->statics_written);
954 }
955 }
956 }
957
958 ipa_free_postorder_info ();
959 free (ptr: order);
960
961 bitmap_obstack_release (&local_info_obstack);
962
963 if (ipa_ref_var_info_summaries != NULL)
964 {
965 delete ipa_ref_var_info_summaries;
966 ipa_ref_var_info_summaries = NULL;
967 }
968
969 if (dump_file)
970 {
971 vec_free (v&: reference_vars_to_consider);
972 reference_vars_to_consider = NULL;
973 }
974 else
975 gcc_checking_assert (!reference_vars_to_consider);
976 return remove_p ? TODO_remove_functions : 0;
977}
978
979/* Return true if we need to write summary of NODE. */
980
981static bool
982write_node_summary_p (struct cgraph_node *node,
983 lto_symtab_encoder_t encoder,
984 bitmap ltrans_statics)
985{
986 ipa_reference_optimization_summary_t info;
987
988 /* See if we have (non-empty) info. */
989 if (!node->definition || node->inlined_to)
990 return false;
991 info = get_reference_optimization_summary (node);
992 if (!info)
993 return false;
994
995 /* See if we want to encode it.
996 Encode also referenced functions since constant folding might turn it into
997 a direct call.
998
999 In future we might also want to include summaries of functions references
1000 by initializers of constant variables references in current unit. */
1001 if (!reachable_from_this_partition_p (node, encoder)
1002 && !referenced_from_this_partition_p (node, encoder))
1003 return false;
1004
1005 /* See if the info has non-empty intersections with vars we want to
1006 encode. */
1007 bitmap_iterator bi;
1008 unsigned int i;
1009 EXECUTE_IF_AND_COMPL_IN_BITMAP (ltrans_statics, info->statics_read, 0,
1010 i, bi)
1011 return true;
1012 EXECUTE_IF_AND_COMPL_IN_BITMAP (ltrans_statics, info->statics_written, 0,
1013 i, bi)
1014 return true;
1015 return false;
1016}
1017
1018/* Stream out BITS&LTRANS_STATICS as list of decls to OB.
1019 LTRANS_STATICS_BITCOUNT specify number of bits in LTRANS_STATICS
1020 or -1. When it is positive, just output -1 when
1021 BITS&LTRANS_STATICS == BITS&LTRANS_STATICS. */
1022
1023static void
1024stream_out_bitmap (struct lto_simple_output_block *ob,
1025 bitmap bits, bitmap ltrans_statics,
1026 int ltrans_statics_bitcount)
1027{
1028 int count = 0;
1029 unsigned int index;
1030 bitmap_iterator bi;
1031 if (bits == all_module_statics)
1032 {
1033 streamer_write_hwi_stream (ob->main_stream, -1);
1034 return;
1035 }
1036 EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi)
1037 count ++;
1038 if (count == ltrans_statics_bitcount)
1039 {
1040 streamer_write_hwi_stream (ob->main_stream, -1);
1041 return;
1042 }
1043 streamer_write_hwi_stream (ob->main_stream, count);
1044 if (!count)
1045 return;
1046 EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi)
1047 {
1048 tree decl = (*reference_vars_to_consider) [index];
1049 lto_output_var_decl_ref (ob->decl_state, ob->main_stream, decl);
1050 }
1051}
1052
1053/* Serialize the ipa info for lto. */
1054
1055static void
1056ipa_reference_write_optimization_summary (void)
1057{
1058 struct lto_simple_output_block *ob
1059 = lto_create_simple_output_block (LTO_section_ipa_reference);
1060 unsigned int count = 0;
1061 int ltrans_statics_bitcount = 0;
1062 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
1063 auto_bitmap ltrans_statics;
1064 int i;
1065
1066 gcc_checking_assert (!reference_vars_to_consider);
1067 vec_alloc (v&: reference_vars_to_consider, nelems: ipa_reference_vars_uids);
1068 reference_vars_to_consider->safe_grow (len: ipa_reference_vars_uids, exact: true);
1069
1070 /* See what variables we are interested in. */
1071 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
1072 {
1073 symtab_node *snode = lto_symtab_encoder_deref (encoder, ref: i);
1074 varpool_node *vnode = dyn_cast <varpool_node *> (p: snode);
1075 int id;
1076
1077 if (vnode
1078 && (id = ipa_reference_var_uid (t: vnode->decl)) != -1
1079 && referenced_from_this_partition_p (vnode, encoder))
1080 {
1081 tree decl = vnode->decl;
1082 bitmap_set_bit (ltrans_statics, id);
1083 (*reference_vars_to_consider)[id] = decl;
1084 ltrans_statics_bitcount ++;
1085 }
1086 }
1087
1088
1089 if (ltrans_statics_bitcount)
1090 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
1091 {
1092 symtab_node *snode = lto_symtab_encoder_deref (encoder, ref: i);
1093 cgraph_node *cnode = dyn_cast <cgraph_node *> (p: snode);
1094 if (cnode && write_node_summary_p (node: cnode, encoder, ltrans_statics))
1095 count++;
1096 }
1097
1098 streamer_write_uhwi_stream (ob->main_stream, count);
1099 if (count)
1100 stream_out_bitmap (ob, bits: ltrans_statics, ltrans_statics,
1101 ltrans_statics_bitcount: -1);
1102
1103 /* Process all of the functions. */
1104 if (ltrans_statics_bitcount)
1105 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
1106 {
1107 symtab_node *snode = lto_symtab_encoder_deref (encoder, ref: i);
1108 cgraph_node *cnode = dyn_cast <cgraph_node *> (p: snode);
1109 if (cnode && write_node_summary_p (node: cnode, encoder, ltrans_statics))
1110 {
1111 ipa_reference_optimization_summary_t info;
1112 int node_ref;
1113
1114 info = get_reference_optimization_summary (node: cnode);
1115 node_ref = lto_symtab_encoder_encode (encoder, snode);
1116 streamer_write_uhwi_stream (ob->main_stream, node_ref);
1117
1118 stream_out_bitmap (ob, bits: info->statics_read, ltrans_statics,
1119 ltrans_statics_bitcount);
1120 stream_out_bitmap (ob, bits: info->statics_written, ltrans_statics,
1121 ltrans_statics_bitcount);
1122 }
1123 }
1124 lto_destroy_simple_output_block (ob);
1125 vec_free (v&: reference_vars_to_consider);
1126 reference_vars_to_consider = NULL;
1127}
1128
1129/* Deserialize the ipa info for lto. */
1130
1131static void
1132ipa_reference_read_optimization_summary (void)
1133{
1134 struct lto_file_decl_data ** file_data_vec
1135 = lto_get_file_decl_data ();
1136 struct lto_file_decl_data * file_data;
1137 unsigned int j = 0;
1138 bitmap_obstack_initialize (&optimization_summary_obstack);
1139
1140 gcc_checking_assert (ipa_ref_opt_sum_summaries == NULL);
1141 ipa_ref_opt_sum_summaries = new ipa_ref_opt_summary_t (symtab);
1142 ipa_ref_opt_sum_summaries->disable_insertion_hook ();
1143 ipa_reference_vars_map = new reference_vars_map_t(257);
1144 varpool_node_hooks
1145 = symtab->add_varpool_removal_hook (hook: varpool_removal_hook, NULL);
1146 ipa_reference_vars_uids = 0;
1147
1148 all_module_statics = BITMAP_ALLOC (obstack: &optimization_summary_obstack);
1149 no_module_statics = BITMAP_ALLOC (obstack: &optimization_summary_obstack);
1150
1151 while ((file_data = file_data_vec[j++]))
1152 {
1153 const char *data;
1154 size_t len;
1155 class lto_input_block *ib
1156 = lto_create_simple_input_block (file_data,
1157 LTO_section_ipa_reference,
1158 &data, &len);
1159 if (ib)
1160 {
1161 unsigned int i;
1162 unsigned int f_count = streamer_read_uhwi (ib);
1163 int b_count;
1164 if (!f_count)
1165 continue;
1166 b_count = streamer_read_hwi (ib);
1167 if (dump_file)
1168 fprintf (stream: dump_file, format: "all module statics:");
1169 for (i = 0; i < (unsigned int)b_count; i++)
1170 {
1171 tree v_decl = lto_input_var_decl_ref (ib, file_data);
1172 bool existed;
1173 bitmap_set_bit (all_module_statics,
1174 ipa_reference_var_get_or_insert_uid
1175 (t: v_decl, existed: &existed));
1176 gcc_checking_assert (!existed);
1177 if (dump_file)
1178 fprintf (stream: dump_file, format: " %s", fndecl_name (v_decl));
1179 }
1180
1181 for (i = 0; i < f_count; i++)
1182 {
1183 unsigned int j, index;
1184 struct cgraph_node *node;
1185 int v_count;
1186 lto_symtab_encoder_t encoder;
1187
1188 index = streamer_read_uhwi (ib);
1189 encoder = file_data->symtab_node_encoder;
1190 node = dyn_cast<cgraph_node *> (p: lto_symtab_encoder_deref
1191 (encoder, ref: index));
1192
1193 ipa_reference_optimization_summary_d *info
1194 = ipa_ref_opt_sum_summaries->get_create (node);
1195
1196 if (dump_file)
1197 fprintf (stream: dump_file,
1198 format: "\nFunction name:%s:\n static read:",
1199 node->dump_asm_name ());
1200
1201 /* Set the statics read. */
1202 v_count = streamer_read_hwi (ib);
1203 if (v_count == -1)
1204 {
1205 info->statics_read = all_module_statics;
1206 if (dump_file)
1207 fprintf (stream: dump_file, format: " all module statics");
1208 }
1209 else if (v_count == 0)
1210 info->statics_read = no_module_statics;
1211 else
1212 {
1213 info->statics_read = BITMAP_ALLOC
1214 (obstack: &optimization_summary_obstack);
1215 for (j = 0; j < (unsigned int)v_count; j++)
1216 {
1217 tree v_decl = lto_input_var_decl_ref (ib, file_data);
1218 bitmap_set_bit (info->statics_read,
1219 ipa_reference_var_uid (t: v_decl));
1220 if (dump_file)
1221 fprintf (stream: dump_file, format: " %s", fndecl_name (v_decl));
1222 }
1223 }
1224
1225 if (dump_file)
1226 fprintf (stream: dump_file,
1227 format: "\n static written:");
1228 /* Set the statics written. */
1229 v_count = streamer_read_hwi (ib);
1230 if (v_count == -1)
1231 {
1232 info->statics_written = all_module_statics;
1233 if (dump_file)
1234 fprintf (stream: dump_file, format: " all module statics");
1235 }
1236 else if (v_count == 0)
1237 info->statics_written = no_module_statics;
1238 else
1239 {
1240 info->statics_written = BITMAP_ALLOC
1241 (obstack: &optimization_summary_obstack);
1242 for (j = 0; j < (unsigned int)v_count; j++)
1243 {
1244 tree v_decl = lto_input_var_decl_ref (ib, file_data);
1245 bitmap_set_bit (info->statics_written,
1246 ipa_reference_var_uid (t: v_decl));
1247 if (dump_file)
1248 fprintf (stream: dump_file, format: " %s", fndecl_name (v_decl));
1249 }
1250 }
1251 if (dump_file)
1252 fprintf (stream: dump_file, format: "\n");
1253 }
1254
1255 lto_destroy_simple_input_block (file_data,
1256 LTO_section_ipa_reference,
1257 ib, data, len);
1258 }
1259 else
1260 /* Fatal error here. We do not want to support compiling ltrans units
1261 with different version of compiler or different flags than
1262 the WPA unit, so this should never happen. */
1263 fatal_error (input_location,
1264 "ipa reference summary is missing in ltrans unit");
1265 }
1266}
1267
1268namespace {
1269
1270const pass_data pass_data_ipa_reference =
1271{
1272 .type: IPA_PASS, /* type */
1273 .name: "static-var", /* name */
1274 .optinfo_flags: OPTGROUP_NONE, /* optinfo_flags */
1275 .tv_id: TV_IPA_REFERENCE, /* tv_id */
1276 .properties_required: 0, /* properties_required */
1277 .properties_provided: 0, /* properties_provided */
1278 .properties_destroyed: 0, /* properties_destroyed */
1279 .todo_flags_start: 0, /* todo_flags_start */
1280 .todo_flags_finish: 0, /* todo_flags_finish */
1281};
1282
1283class pass_ipa_reference : public ipa_opt_pass_d
1284{
1285public:
1286 pass_ipa_reference (gcc::context *ctxt)
1287 : ipa_opt_pass_d (pass_data_ipa_reference, ctxt,
1288 NULL, /* generate_summary */
1289 NULL, /* write_summary */
1290 NULL, /* read_summary */
1291 ipa_reference_write_optimization_summary, /*
1292 write_optimization_summary */
1293 ipa_reference_read_optimization_summary, /*
1294 read_optimization_summary */
1295 NULL, /* stmt_fixup */
1296 0, /* function_transform_todo_flags_start */
1297 NULL, /* function_transform */
1298 NULL) /* variable_transform */
1299 {}
1300
1301 /* opt_pass methods: */
1302 bool gate (function *) final override
1303 {
1304 return ((in_lto_p || flag_ipa_reference)
1305 /* Don't bother doing anything if the program has errors. */
1306 && !seen_error ());
1307 }
1308
1309 unsigned int execute (function *) final override { return propagate (); }
1310
1311}; // class pass_ipa_reference
1312
1313} // anon namespace
1314
1315ipa_opt_pass_d *
1316make_pass_ipa_reference (gcc::context *ctxt)
1317{
1318 return new pass_ipa_reference (ctxt);
1319}
1320
1321/* Reset all state within ipa-reference.cc so that we can rerun the compiler
1322 within the same process. For use by toplev::finalize. */
1323
1324void
1325ipa_reference_cc_finalize (void)
1326{
1327 if (ipa_ref_opt_sum_summaries != NULL)
1328 {
1329 delete ipa_ref_opt_sum_summaries;
1330 ipa_ref_opt_sum_summaries = NULL;
1331 delete ipa_reference_vars_map;
1332 ipa_reference_vars_map = NULL;
1333 symtab->remove_varpool_removal_hook (entry: varpool_node_hooks);
1334 }
1335
1336 if (ipa_init_p)
1337 {
1338 bitmap_obstack_release (&optimization_summary_obstack);
1339 ipa_init_p = false;
1340 }
1341}
1342

source code of gcc/ipa-reference.cc