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 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify it under |
8 | the terms of the GNU General Public License as published by the Free |
9 | Software Foundation; either version 3, or (at your option) any later |
10 | version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GCC; see the file 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 | |
57 | struct 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 | |
68 | struct 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 | |
76 | struct ipa_reference_optimization_summary_d |
77 | { |
78 | bitmap statics_read; |
79 | bitmap statics_written; |
80 | }; |
81 | |
82 | typedef ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t; |
83 | typedef ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t; |
84 | typedef ipa_reference_optimization_summary_d * |
85 | ipa_reference_optimization_summary_t; |
86 | |
87 | struct 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 | |
93 | typedef 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. */ |
97 | typedef hash_map<tree, int> reference_vars_map_t; |
98 | static reference_vars_map_t *ipa_reference_vars_map; |
99 | static int ipa_reference_vars_uids; |
100 | static vec<tree> *reference_vars_to_consider; |
101 | varpool_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. */ |
106 | static bitmap all_module_statics; |
107 | /* Zero bitmap. */ |
108 | static bitmap no_module_statics; |
109 | /* Set of all statics that should be ignored because they are touched by |
110 | -fno-ipa-reference code. */ |
111 | static bitmap ignore_module_statics; |
112 | |
113 | /* Obstack holding bitmaps of local analysis (live from analysis to |
114 | propagation) */ |
115 | static bitmap_obstack local_info_obstack; |
116 | /* Obstack holding global analysis live forever. */ |
117 | static bitmap_obstack optimization_summary_obstack; |
118 | |
119 | class ipa_ref_var_info_summary_t: public fast_function_summary |
120 | <ipa_reference_vars_info_d *, va_heap> |
121 | { |
122 | public: |
123 | ipa_ref_var_info_summary_t (symbol_table *symtab): |
124 | fast_function_summary <ipa_reference_vars_info_d *, va_heap> (symtab) {} |
125 | }; |
126 | |
127 | static ipa_ref_var_info_summary_t *ipa_ref_var_info_summaries = NULL; |
128 | |
129 | class ipa_ref_opt_summary_t: public fast_function_summary |
130 | <ipa_reference_optimization_summary_d *, va_heap> |
131 | { |
132 | public: |
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 | |
143 | static ipa_ref_opt_summary_t *ipa_ref_opt_sum_summaries = NULL; |
144 | |
145 | /* Return ID used by ipa-reference bitmaps. -1 if failed. */ |
146 | int |
147 | ipa_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 */ |
160 | int |
161 | ipa_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. */ |
171 | static inline ipa_reference_vars_info_t |
172 | get_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. */ |
182 | static inline ipa_reference_optimization_summary_t |
183 | get_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 | |
198 | bitmap |
199 | ipa_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 | |
227 | bitmap |
228 | ipa_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. */ |
253 | static bool |
254 | is_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 | |
287 | static inline bool |
288 | is_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 | |
305 | static const char * |
306 | get_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. */ |
312 | static void |
313 | dump_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 | |
334 | static bool |
335 | union_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 | |
365 | static bitmap |
366 | copy_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 | |
385 | static void |
386 | propagate_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 | |
443 | static void |
444 | varpool_removal_hook (varpool_node *node, void *) |
445 | { |
446 | ipa_reference_vars_map->remove (k: node->decl); |
447 | } |
448 | |
449 | static bool ipa_init_p = false; |
450 | |
451 | /* The init routine for analyzing global static variable usage. See |
452 | comments at top for description. */ |
453 | static void |
454 | ipa_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 | |
488 | static ipa_reference_local_vars_info_t |
489 | init_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 | |
505 | static void |
506 | analyze_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 | |
558 | void |
559 | ipa_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 | |
572 | void |
573 | ipa_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 | |
590 | static void |
591 | generate_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 | |
658 | static void |
659 | read_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 | |
690 | static void |
691 | get_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 | |
737 | static bool |
738 | ignore_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 | |
754 | static unsigned int |
755 | propagate (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 | |
981 | static bool |
982 | write_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<RANS_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<RANS_STATICS == BITS<RANS_STATICS. */ |
1022 | |
1023 | static void |
1024 | stream_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 | |
1055 | static void |
1056 | ipa_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 | |
1131 | static void |
1132 | ipa_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 | |
1268 | namespace { |
1269 | |
1270 | const 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 | |
1283 | class pass_ipa_reference : public ipa_opt_pass_d |
1284 | { |
1285 | public: |
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 | |
1315 | ipa_opt_pass_d * |
1316 | make_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 | |
1324 | void |
1325 | ipa_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 | |