]>
Commit | Line | Data |
---|---|---|
f7d118a9 | 1 | /* Callgraph based analysis of static variables. |
7cf0dbf3 | 2 | Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 |
3 | Free Software Foundation, Inc. | |
f7d118a9 | 4 | Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> |
5 | ||
6 | This file is part of GCC. | |
7 | ||
8 | GCC is free software; you can redistribute it and/or modify it under | |
9 | the terms of the GNU General Public License as published by the Free | |
8c4c00c1 | 10 | Software Foundation; either version 3, or (at your option) any later |
f7d118a9 | 11 | version. |
12 | ||
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
8c4c00c1 | 19 | along with GCC; see the file COPYING3. If not see |
20 | <http://www.gnu.org/licenses/>. */ | |
f7d118a9 | 21 | |
22 | /* This file gathers information about how variables whose scope is | |
48e1416a | 23 | confined to the compilation unit are used. |
f7d118a9 | 24 | |
8dfbf71d | 25 | The transitive call site specific clobber effects are computed |
f7d118a9 | 26 | for the variables whose scope is contained within this compilation |
27 | unit. | |
28 | ||
29 | First each function and static variable initialization is analyzed | |
30 | to determine which local static variables are either read, written, | |
31 | or have their address taken. Any local static that has its address | |
32 | taken is removed from consideration. Once the local read and | |
33 | writes are determined, a transitive closure of this information is | |
34 | performed over the call graph to determine the worst case set of | |
35 | side effects of each call. In later parts of the compiler, these | |
36 | local and global sets are examined to make the call clobbering less | |
37 | traumatic, promote some statics to registers, and improve aliasing | |
8dfbf71d | 38 | information. */ |
f7d118a9 | 39 | |
40 | #include "config.h" | |
41 | #include "system.h" | |
42 | #include "coretypes.h" | |
43 | #include "tm.h" | |
44 | #include "tree.h" | |
45 | #include "tree-flow.h" | |
46 | #include "tree-inline.h" | |
47 | #include "tree-pass.h" | |
48 | #include "langhooks.h" | |
49 | #include "pointer-set.h" | |
5863771b | 50 | #include "splay-tree.h" |
f7d118a9 | 51 | #include "ggc.h" |
52 | #include "ipa-utils.h" | |
53 | #include "ipa-reference.h" | |
75a70cf9 | 54 | #include "gimple.h" |
f7d118a9 | 55 | #include "cgraph.h" |
f7d118a9 | 56 | #include "flags.h" |
57 | #include "timevar.h" | |
58 | #include "diagnostic.h" | |
59 | #include "langhooks.h" | |
7f385784 | 60 | #include "data-streamer.h" |
7bfefa9d | 61 | #include "lto-streamer.h" |
62 | ||
7bfefa9d | 63 | static void remove_node_data (struct cgraph_node *node, |
64 | void *data ATTRIBUTE_UNUSED); | |
65 | static void duplicate_node_data (struct cgraph_node *src, | |
66 | struct cgraph_node *dst, | |
67 | void *data ATTRIBUTE_UNUSED); | |
f7d118a9 | 68 | |
86844d6c | 69 | /* The static variables defined within the compilation unit that are |
48e1416a | 70 | loaded or stored directly by function that owns this structure. */ |
86844d6c | 71 | |
48e1416a | 72 | struct ipa_reference_local_vars_info_d |
86844d6c | 73 | { |
74 | bitmap statics_read; | |
75 | bitmap statics_written; | |
86844d6c | 76 | }; |
77 | ||
78 | /* Statics that are read and written by some set of functions. The | |
79 | local ones are based on the loads and stores local to the function. | |
80 | The global ones are based on the local info as well as the | |
db5a3693 | 81 | transitive closure of the functions that are called. */ |
86844d6c | 82 | |
83 | struct ipa_reference_global_vars_info_d | |
84 | { | |
85 | bitmap statics_read; | |
86 | bitmap statics_written; | |
db5a3693 | 87 | }; |
88 | ||
0a10fd82 | 89 | /* Information we save about every function after ipa-reference is completed. */ |
db5a3693 | 90 | |
91 | struct ipa_reference_optimization_summary_d | |
92 | { | |
86844d6c | 93 | bitmap statics_not_read; |
94 | bitmap statics_not_written; | |
95 | }; | |
96 | ||
97 | typedef struct ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t; | |
98 | typedef struct ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t; | |
db5a3693 | 99 | typedef struct ipa_reference_optimization_summary_d *ipa_reference_optimization_summary_t; |
100 | ||
48e1416a | 101 | struct ipa_reference_vars_info_d |
86844d6c | 102 | { |
db5a3693 | 103 | struct ipa_reference_local_vars_info_d local; |
104 | struct ipa_reference_global_vars_info_d global; | |
86844d6c | 105 | }; |
106 | ||
107 | typedef struct ipa_reference_vars_info_d *ipa_reference_vars_info_t; | |
108 | ||
f7d118a9 | 109 | /* This splay tree contains all of the static variables that are |
db5a3693 | 110 | being considered by the compilation level alias analysis. */ |
111 | static splay_tree reference_vars_to_consider; | |
f7d118a9 | 112 | |
f7d118a9 | 113 | /* A bit is set for every module static we are considering. This is |
114 | ored into the local info when asm code is found that clobbers all | |
115 | memory. */ | |
116 | static bitmap all_module_statics; | |
117 | ||
ed4f5c92 | 118 | /* Obstack holding bitmaps of local analysis (live from analysis to |
119 | propagation) */ | |
120 | static bitmap_obstack local_info_obstack; | |
121 | /* Obstack holding global analysis live forever. */ | |
db5a3693 | 122 | static bitmap_obstack optimization_summary_obstack; |
f7d118a9 | 123 | |
50828ed8 | 124 | /* Holders of ipa cgraph hooks: */ |
86844d6c | 125 | static struct cgraph_2node_hook_list *node_duplication_hook_holder; |
126 | static struct cgraph_node_hook_list *node_removal_hook_holder; | |
50828ed8 | 127 | |
86844d6c | 128 | /* Vector where the reference var infos are actually stored. */ |
129 | DEF_VEC_P (ipa_reference_vars_info_t); | |
130 | DEF_VEC_ALLOC_P (ipa_reference_vars_info_t, heap); | |
131 | static VEC (ipa_reference_vars_info_t, heap) *ipa_reference_vars_vector; | |
db5a3693 | 132 | DEF_VEC_P (ipa_reference_optimization_summary_t); |
133 | DEF_VEC_ALLOC_P (ipa_reference_optimization_summary_t, heap); | |
134 | static VEC (ipa_reference_optimization_summary_t, heap) *ipa_reference_opt_sum_vector; | |
86844d6c | 135 | |
f7d118a9 | 136 | /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ |
137 | static inline ipa_reference_vars_info_t | |
86844d6c | 138 | get_reference_vars_info (struct cgraph_node *node) |
139 | { | |
140 | if (!ipa_reference_vars_vector | |
db5a3693 | 141 | || VEC_length (ipa_reference_vars_info_t, |
142 | ipa_reference_vars_vector) <= (unsigned int) node->uid) | |
86844d6c | 143 | return NULL; |
db5a3693 | 144 | return VEC_index (ipa_reference_vars_info_t, ipa_reference_vars_vector, |
145 | node->uid); | |
86844d6c | 146 | } |
147 | ||
148 | /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ | |
db5a3693 | 149 | static inline ipa_reference_optimization_summary_t |
150 | get_reference_optimization_summary (struct cgraph_node *node) | |
f7d118a9 | 151 | { |
db5a3693 | 152 | if (!ipa_reference_opt_sum_vector |
153 | || (VEC_length (ipa_reference_optimization_summary_t, | |
d2d73492 | 154 | ipa_reference_opt_sum_vector) |
db5a3693 | 155 | <= (unsigned int) node->uid)) |
f7d118a9 | 156 | return NULL; |
db5a3693 | 157 | return VEC_index (ipa_reference_optimization_summary_t, ipa_reference_opt_sum_vector, |
158 | node->uid); | |
f7d118a9 | 159 | } |
160 | ||
db5a3693 | 161 | /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ |
162 | static inline void | |
163 | set_reference_vars_info (struct cgraph_node *node, | |
164 | ipa_reference_vars_info_t info) | |
f7d118a9 | 165 | { |
db5a3693 | 166 | if (!ipa_reference_vars_vector |
167 | || VEC_length (ipa_reference_vars_info_t, | |
168 | ipa_reference_vars_vector) <= (unsigned int) node->uid) | |
169 | VEC_safe_grow_cleared (ipa_reference_vars_info_t, heap, | |
170 | ipa_reference_vars_vector, node->uid + 1); | |
171 | VEC_replace (ipa_reference_vars_info_t, ipa_reference_vars_vector, | |
172 | node->uid, info); | |
f7d118a9 | 173 | } |
174 | ||
db5a3693 | 175 | /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ |
176 | static inline void | |
177 | set_reference_optimization_summary (struct cgraph_node *node, | |
178 | ipa_reference_optimization_summary_t info) | |
f7d118a9 | 179 | { |
db5a3693 | 180 | if (!ipa_reference_opt_sum_vector |
181 | || (VEC_length (ipa_reference_optimization_summary_t, | |
182 | ipa_reference_opt_sum_vector) | |
183 | <= (unsigned int) node->uid)) | |
184 | VEC_safe_grow_cleared (ipa_reference_optimization_summary_t, | |
185 | heap, ipa_reference_opt_sum_vector, node->uid + 1); | |
186 | VEC_replace (ipa_reference_optimization_summary_t, | |
187 | ipa_reference_opt_sum_vector, node->uid, info); | |
f7d118a9 | 188 | } |
189 | ||
190 | /* Return a bitmap indexed by_DECL_UID uid for the static variables | |
191 | that are not read during the execution of the function FN. Returns | |
192 | NULL if no data is available. */ | |
193 | ||
48e1416a | 194 | bitmap |
195 | ipa_reference_get_not_read_global (struct cgraph_node *fn) | |
f7d118a9 | 196 | { |
db5a3693 | 197 | ipa_reference_optimization_summary_t info; |
198 | ||
b2c2e188 | 199 | info = get_reference_optimization_summary (cgraph_function_node (fn, NULL)); |
db5a3693 | 200 | if (info) |
201 | return info->statics_not_read; | |
7d0d0ce1 | 202 | else if (flags_from_decl_or_type (fn->symbol.decl) & ECF_LEAF) |
7bd95dfd | 203 | return all_module_statics; |
f7d118a9 | 204 | else |
205 | return NULL; | |
206 | } | |
207 | ||
208 | /* Return a bitmap indexed by DECL_UID uid for the static variables | |
209 | that are not written during the execution of the function FN. Note | |
210 | that variables written may or may not be read during the function | |
211 | call. Returns NULL if no data is available. */ | |
212 | ||
48e1416a | 213 | bitmap |
214 | ipa_reference_get_not_written_global (struct cgraph_node *fn) | |
f7d118a9 | 215 | { |
db5a3693 | 216 | ipa_reference_optimization_summary_t info; |
217 | ||
218 | info = get_reference_optimization_summary (fn); | |
219 | if (info) | |
220 | return info->statics_not_written; | |
7d0d0ce1 | 221 | else if (flags_from_decl_or_type (fn->symbol.decl) & ECF_LEAF) |
7bd95dfd | 222 | return all_module_statics; |
f7d118a9 | 223 | else |
224 | return NULL; | |
225 | } | |
226 | ||
227 | \f | |
228 | ||
229 | /* Add VAR to all_module_statics and the two | |
230 | reference_vars_to_consider* sets. */ | |
231 | ||
48e1416a | 232 | static inline void |
233 | add_static_var (tree var) | |
f7d118a9 | 234 | { |
235 | int uid = DECL_UID (var); | |
ed4f5c92 | 236 | gcc_assert (TREE_CODE (var) == VAR_DECL); |
346beec7 | 237 | if (dump_file) |
238 | splay_tree_insert (reference_vars_to_consider, | |
239 | uid, (splay_tree_value)var); | |
240 | bitmap_set_bit (all_module_statics, uid); | |
f7d118a9 | 241 | } |
242 | ||
243 | /* Return true if the variable T is the right kind of static variable to | |
244 | perform compilation unit scope escape analysis. */ | |
245 | ||
48e1416a | 246 | static inline bool |
f8b7e3ec | 247 | is_proper_for_analysis (tree t) |
f7d118a9 | 248 | { |
249 | /* If the variable has the "used" attribute, treat it as if it had a | |
250 | been touched by the devil. */ | |
83a23b05 | 251 | if (DECL_PRESERVE_P (t)) |
f7d118a9 | 252 | return false; |
253 | ||
254 | /* Do not want to do anything with volatile except mark any | |
255 | function that uses one to be not const or pure. */ | |
48e1416a | 256 | if (TREE_THIS_VOLATILE (t)) |
f7d118a9 | 257 | return false; |
258 | ||
d2d73492 | 259 | /* We do not need to analyze readonly vars, we already know they do not |
260 | alias. */ | |
261 | if (TREE_READONLY (t)) | |
262 | return false; | |
263 | ||
f7d118a9 | 264 | /* This is a variable we care about. Check if we have seen it |
265 | before, and if not add it the set of variables we care about. */ | |
d97be713 | 266 | if (all_module_statics |
267 | && !bitmap_bit_p (all_module_statics, DECL_UID (t))) | |
f7d118a9 | 268 | add_static_var (t); |
269 | ||
270 | return true; | |
271 | } | |
272 | ||
f7d118a9 | 273 | /* Lookup the tree node for the static variable that has UID and |
23943319 | 274 | convert the name to a string for debugging. */ |
f7d118a9 | 275 | |
276 | static const char * | |
277 | get_static_name (int index) | |
278 | { | |
48e1416a | 279 | splay_tree_node stn = |
f7d118a9 | 280 | splay_tree_lookup (reference_vars_to_consider, index); |
281 | if (stn) | |
282 | return lang_hooks.decl_printable_name ((tree)(stn->value), 2); | |
283 | return NULL; | |
284 | } | |
285 | ||
86844d6c | 286 | /* Or in all of the bits from every callee of X into X_GLOBAL, the caller's cycle, |
287 | bit vector. There are several cases to check to avoid the sparse | |
f7d118a9 | 288 | bitmap oring. */ |
289 | ||
290 | static void | |
86844d6c | 291 | propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x) |
f7d118a9 | 292 | { |
f7d118a9 | 293 | struct cgraph_edge *e; |
48e1416a | 294 | for (e = x->callees; e; e = e->next_callee) |
f7d118a9 | 295 | { |
7bd95dfd | 296 | enum availability avail; |
b2c2e188 | 297 | struct cgraph_node *y = cgraph_function_node (e->callee, &avail); |
f7d118a9 | 298 | |
b2c2e188 | 299 | if (!y) |
300 | continue; | |
ef378c27 | 301 | /* Only look into nodes we can propagate something. */ |
7bd95dfd | 302 | if (avail > AVAIL_OVERWRITABLE |
303 | || (avail == AVAIL_OVERWRITABLE | |
7d0d0ce1 | 304 | && (flags_from_decl_or_type (y->symbol.decl) & ECF_LEAF))) |
f7d118a9 | 305 | { |
7d0d0ce1 | 306 | int flags = flags_from_decl_or_type (y->symbol.decl); |
86844d6c | 307 | if (get_reference_vars_info (y)) |
f7d118a9 | 308 | { |
48e1416a | 309 | ipa_reference_vars_info_t y_info |
86844d6c | 310 | = get_reference_vars_info (y); |
db5a3693 | 311 | ipa_reference_global_vars_info_t y_global = &y_info->global; |
86844d6c | 312 | |
313 | /* Calls in current cycle do not have global computed yet. */ | |
db5a3693 | 314 | if (!y_global->statics_read) |
86844d6c | 315 | continue; |
48e1416a | 316 | |
d2d73492 | 317 | /* If function is declared const, it reads no memory even if it |
318 | seems so to local analysis. */ | |
319 | if (flags & ECF_CONST) | |
320 | continue; | |
321 | ||
f7d118a9 | 322 | if (x_global->statics_read |
323 | != all_module_statics) | |
324 | { | |
48e1416a | 325 | if (y_global->statics_read |
f7d118a9 | 326 | == all_module_statics) |
327 | { | |
328 | BITMAP_FREE (x_global->statics_read); | |
48e1416a | 329 | x_global->statics_read |
f7d118a9 | 330 | = all_module_statics; |
331 | } | |
332 | /* Skip bitmaps that are pointer equal to node's bitmap | |
333 | (no reason to spin within the cycle). */ | |
48e1416a | 334 | else if (x_global->statics_read |
f7d118a9 | 335 | != y_global->statics_read) |
336 | bitmap_ior_into (x_global->statics_read, | |
337 | y_global->statics_read); | |
338 | } | |
48e1416a | 339 | |
d2d73492 | 340 | /* If function is declared pure, it has no stores even if it |
341 | seems so to local analysis; If we can not return from here, | |
342 | we can safely ignore the call. */ | |
343 | if ((flags & ECF_PURE) | |
344 | || cgraph_edge_cannot_lead_to_return (e)) | |
345 | continue; | |
346 | ||
48e1416a | 347 | if (x_global->statics_written |
f7d118a9 | 348 | != all_module_statics) |
349 | { | |
48e1416a | 350 | if (y_global->statics_written |
f7d118a9 | 351 | == all_module_statics) |
352 | { | |
353 | BITMAP_FREE (x_global->statics_written); | |
48e1416a | 354 | x_global->statics_written |
f7d118a9 | 355 | = all_module_statics; |
356 | } | |
357 | /* Skip bitmaps that are pointer equal to node's bitmap | |
358 | (no reason to spin within the cycle). */ | |
48e1416a | 359 | else if (x_global->statics_written |
f7d118a9 | 360 | != y_global->statics_written) |
361 | bitmap_ior_into (x_global->statics_written, | |
362 | y_global->statics_written); | |
363 | } | |
364 | } | |
48e1416a | 365 | else |
ed4f5c92 | 366 | gcc_unreachable (); |
f7d118a9 | 367 | } |
368 | } | |
369 | } | |
370 | ||
f7d118a9 | 371 | /* The init routine for analyzing global static variable usage. See |
372 | comments at top for description. */ | |
48e1416a | 373 | static void |
374 | ipa_init (void) | |
f7d118a9 | 375 | { |
7bfefa9d | 376 | static bool init_p = false; |
377 | ||
378 | if (init_p) | |
379 | return; | |
380 | ||
381 | init_p = true; | |
382 | ||
db5a3693 | 383 | if (dump_file) |
384 | reference_vars_to_consider = splay_tree_new (splay_tree_compare_ints, 0, 0); | |
f7d118a9 | 385 | |
ed4f5c92 | 386 | bitmap_obstack_initialize (&local_info_obstack); |
db5a3693 | 387 | bitmap_obstack_initialize (&optimization_summary_obstack); |
d2d73492 | 388 | all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack); |
2116cc0c | 389 | |
7bfefa9d | 390 | node_removal_hook_holder = |
391 | cgraph_add_node_removal_hook (&remove_node_data, NULL); | |
392 | node_duplication_hook_holder = | |
393 | cgraph_add_node_duplication_hook (&duplicate_node_data, NULL); | |
f7d118a9 | 394 | } |
395 | ||
7bfefa9d | 396 | |
cb886925 | 397 | /* Set up the persistent info for FN. */ |
f7d118a9 | 398 | |
cb886925 | 399 | static ipa_reference_local_vars_info_t |
400 | init_function_info (struct cgraph_node *fn) | |
f7d118a9 | 401 | { |
48e1416a | 402 | ipa_reference_vars_info_t info |
cda6870f | 403 | = XCNEW (struct ipa_reference_vars_info_d); |
f7d118a9 | 404 | |
405 | /* Add the info to the tree's annotation. */ | |
86844d6c | 406 | set_reference_vars_info (fn, info); |
f7d118a9 | 407 | |
db5a3693 | 408 | info->local.statics_read = BITMAP_ALLOC (&local_info_obstack); |
409 | info->local.statics_written = BITMAP_ALLOC (&local_info_obstack); | |
f7d118a9 | 410 | |
db5a3693 | 411 | return &info->local; |
cb886925 | 412 | } |
413 | ||
7bfefa9d | 414 | |
cb886925 | 415 | /* This is the main routine for finding the reference patterns for |
416 | global variables within a function FN. */ | |
7bfefa9d | 417 | |
cb886925 | 418 | static void |
419 | analyze_function (struct cgraph_node *fn) | |
420 | { | |
f589330e | 421 | ipa_reference_local_vars_info_t local; |
f8b7e3ec | 422 | struct ipa_ref *ref; |
423 | int i; | |
424 | tree var; | |
cb886925 | 425 | |
f8b7e3ec | 426 | local = init_function_info (fn); |
7d0d0ce1 | 427 | for (i = 0; ipa_ref_list_reference_iterate (&fn->symbol.ref_list, i, ref); i++) |
cb886925 | 428 | { |
04ec15fa | 429 | if (!symtab_variable_p (ref->referred)) |
f8b7e3ec | 430 | continue; |
7d0d0ce1 | 431 | var = ipa_ref_varpool_node (ref)->symbol.decl; |
a7847fbd | 432 | if (!is_proper_for_analysis (var)) |
f8b7e3ec | 433 | continue; |
434 | switch (ref->use) | |
cb886925 | 435 | { |
f8b7e3ec | 436 | case IPA_REF_LOAD: |
437 | bitmap_set_bit (local->statics_read, DECL_UID (var)); | |
438 | break; | |
439 | case IPA_REF_STORE: | |
023a28e1 | 440 | if (ipa_ref_cannot_lead_to_return (ref)) |
441 | break; | |
f8b7e3ec | 442 | bitmap_set_bit (local->statics_written, DECL_UID (var)); |
f8b7e3ec | 443 | break; |
444 | case IPA_REF_ADDR: | |
f8b7e3ec | 445 | break; |
cb886925 | 446 | } |
cb886925 | 447 | } |
f7d118a9 | 448 | |
d2d73492 | 449 | if (cgraph_node_cannot_return (fn)) |
450 | bitmap_clear (local->statics_written); | |
f7d118a9 | 451 | } |
452 | ||
86844d6c | 453 | static bitmap |
454 | copy_global_bitmap (bitmap src) | |
455 | { | |
456 | bitmap dst; | |
457 | if (!src) | |
458 | return NULL; | |
d2d73492 | 459 | if (src == all_module_statics) |
460 | return all_module_statics; | |
db5a3693 | 461 | dst = BITMAP_ALLOC (&optimization_summary_obstack); |
86844d6c | 462 | bitmap_copy (dst, src); |
463 | return dst; | |
464 | } | |
465 | ||
f8b7e3ec | 466 | |
86844d6c | 467 | /* Called when new clone is inserted to callgraph late. */ |
468 | ||
469 | static void | |
470 | duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst, | |
471 | void *data ATTRIBUTE_UNUSED) | |
472 | { | |
db5a3693 | 473 | ipa_reference_optimization_summary_t ginfo; |
474 | ipa_reference_optimization_summary_t dst_ginfo; | |
86844d6c | 475 | |
db5a3693 | 476 | ginfo = get_reference_optimization_summary (src); |
f8b7e3ec | 477 | if (!ginfo) |
86844d6c | 478 | return; |
db5a3693 | 479 | dst_ginfo = XCNEW (struct ipa_reference_optimization_summary_d); |
480 | set_reference_optimization_summary (dst, dst_ginfo); | |
481 | dst_ginfo->statics_not_read = copy_global_bitmap (ginfo->statics_not_read); | |
482 | dst_ginfo->statics_not_written = copy_global_bitmap (ginfo->statics_not_written); | |
86844d6c | 483 | } |
484 | ||
485 | /* Called when node is removed. */ | |
486 | ||
487 | static void | |
488 | remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) | |
489 | { | |
db5a3693 | 490 | ipa_reference_optimization_summary_t ginfo; |
491 | ginfo = get_reference_optimization_summary (node); | |
492 | if (ginfo) | |
493 | { | |
494 | if (ginfo->statics_not_read | |
495 | && ginfo->statics_not_read != all_module_statics) | |
496 | BITMAP_FREE (ginfo->statics_not_read); | |
497 | ||
498 | if (ginfo->statics_not_written | |
499 | && ginfo->statics_not_written != all_module_statics) | |
500 | BITMAP_FREE (ginfo->statics_not_written); | |
501 | free (ginfo); | |
502 | set_reference_optimization_summary (node, NULL); | |
503 | } | |
86844d6c | 504 | } |
505 | ||
cb886925 | 506 | /* Analyze each function in the cgraph to see which global or statics |
507 | are read or written. */ | |
508 | ||
48e1416a | 509 | static void |
cb886925 | 510 | generate_summary (void) |
f7d118a9 | 511 | { |
512 | struct cgraph_node *node; | |
cb886925 | 513 | unsigned int index; |
514 | bitmap_iterator bi; | |
cb886925 | 515 | bitmap bm_temp; |
48e1416a | 516 | |
f7d118a9 | 517 | ipa_init (); |
ed4f5c92 | 518 | bm_temp = BITMAP_ALLOC (&local_info_obstack); |
f7d118a9 | 519 | |
f8b7e3ec | 520 | /* Process all of the functions next. */ |
7c455d87 | 521 | FOR_EACH_DEFINED_FUNCTION (node) |
522 | analyze_function (node); | |
f7d118a9 | 523 | |
cb886925 | 524 | if (dump_file) |
f7d118a9 | 525 | EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi) |
526 | { | |
cb886925 | 527 | fprintf (dump_file, "\nPromotable global:%s", |
528 | get_static_name (index)); | |
f7d118a9 | 529 | } |
48e1416a | 530 | |
cb886925 | 531 | BITMAP_FREE(bm_temp); |
48e1416a | 532 | |
f7d118a9 | 533 | if (dump_file) |
7c455d87 | 534 | FOR_EACH_DEFINED_FUNCTION (node) |
86844d6c | 535 | if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) |
f7d118a9 | 536 | { |
f7d118a9 | 537 | ipa_reference_local_vars_info_t l; |
cb886925 | 538 | unsigned int index; |
f7d118a9 | 539 | bitmap_iterator bi; |
48e1416a | 540 | |
db5a3693 | 541 | l = &get_reference_vars_info (node)->local; |
48e1416a | 542 | fprintf (dump_file, |
543 | "\nFunction name:%s/%i:", | |
18841b0c | 544 | cgraph_node_asm_name (node), node->symbol.order); |
f7d118a9 | 545 | fprintf (dump_file, "\n locals read: "); |
f589330e | 546 | if (l->statics_read) |
547 | EXECUTE_IF_SET_IN_BITMAP (l->statics_read, | |
548 | 0, index, bi) | |
549 | { | |
550 | fprintf (dump_file, "%s ", | |
551 | get_static_name (index)); | |
552 | } | |
f7d118a9 | 553 | fprintf (dump_file, "\n locals written: "); |
f589330e | 554 | if (l->statics_written) |
555 | EXECUTE_IF_SET_IN_BITMAP (l->statics_written, | |
556 | 0, index, bi) | |
557 | { | |
558 | fprintf(dump_file, "%s ", | |
559 | get_static_name (index)); | |
560 | } | |
f7d118a9 | 561 | } |
cb886925 | 562 | } |
563 | \f | |
d2d73492 | 564 | /* Set READ_ALL/WRITE_ALL based on decl flags of NODE. */ |
db5a3693 | 565 | |
ef378c27 | 566 | static void |
d2d73492 | 567 | read_write_all_from_decl (struct cgraph_node *node, bool * read_all, |
568 | bool * write_all) | |
ef378c27 | 569 | { |
7d0d0ce1 | 570 | tree decl = node->symbol.decl; |
ef378c27 | 571 | int flags = flags_from_decl_or_type (decl); |
7bd95dfd | 572 | if ((flags & ECF_LEAF) |
573 | && cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) | |
574 | ; | |
575 | else if (flags & ECF_CONST) | |
ef378c27 | 576 | ; |
d2d73492 | 577 | else if ((flags & ECF_PURE) |
578 | || cgraph_node_cannot_return (node)) | |
7bd95dfd | 579 | { |
580 | *read_all = true; | |
581 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
582 | fprintf (dump_file, " %s/%i -> read all\n", | |
18841b0c | 583 | cgraph_node_asm_name (node), node->symbol.order); |
7bd95dfd | 584 | } |
ef378c27 | 585 | else |
586 | { | |
587 | /* TODO: To be able to produce sane results, we should also handle | |
db5a3693 | 588 | common builtins, in particular throw. */ |
ef378c27 | 589 | *read_all = true; |
d2d73492 | 590 | *write_all = true; |
7bd95dfd | 591 | if (dump_file && (dump_flags & TDF_DETAILS)) |
592 | fprintf (dump_file, " %s/%i -> read all, write all\n", | |
18841b0c | 593 | cgraph_node_asm_name (node), node->symbol.order); |
ef378c27 | 594 | } |
595 | } | |
596 | ||
cb886925 | 597 | /* Produce the global information by preforming a transitive closure |
db5a3693 | 598 | on the local information that was produced by ipa_analyze_function */ |
cb886925 | 599 | |
600 | static unsigned int | |
601 | propagate (void) | |
602 | { | |
603 | struct cgraph_node *node; | |
a7847fbd | 604 | struct varpool_node *vnode; |
cb886925 | 605 | struct cgraph_node *w; |
606 | struct cgraph_node **order = | |
607 | XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); | |
7771d558 | 608 | int order_pos; |
cb886925 | 609 | int i; |
610 | ||
48e1416a | 611 | if (dump_file) |
cb886925 | 612 | dump_cgraph (dump_file); |
f7d118a9 | 613 | |
db5a3693 | 614 | ipa_discover_readonly_nonaddressable_vars (); |
f8b7e3ec | 615 | generate_summary (); |
616 | ||
9d75589a | 617 | /* Now we know what vars are really statics; prune out those that aren't. */ |
a7847fbd | 618 | FOR_EACH_VARIABLE (vnode) |
619 | if (vnode->symbol.externally_visible | |
620 | || TREE_ADDRESSABLE (vnode->symbol.decl) | |
621 | || TREE_READONLY (vnode->symbol.decl) | |
622 | || !is_proper_for_analysis (vnode->symbol.decl) | |
623 | || !vnode->analyzed) | |
624 | bitmap_clear_bit (all_module_statics, DECL_UID (vnode->symbol.decl)); | |
625 | ||
626 | /* Forget info we collected "just for fun" on variables that turned out to be | |
627 | non-local. */ | |
628 | FOR_EACH_DEFINED_FUNCTION (node) | |
629 | { | |
630 | ipa_reference_local_vars_info_t node_l; | |
631 | ||
632 | node_l = &get_reference_vars_info (node)->local; | |
633 | if (node_l->statics_read != all_module_statics) | |
634 | bitmap_and_into (node_l->statics_read, all_module_statics); | |
635 | if (node_l->statics_written != all_module_statics) | |
636 | bitmap_and_into (node_l->statics_written, all_module_statics); | |
637 | } | |
638 | ||
9d75589a | 639 | /* Propagate the local information through the call graph to produce |
f7d118a9 | 640 | the global information. All the nodes within a cycle will have |
641 | the same info so we collapse cycles first. Then we can do the | |
642 | propagation in one pass from the leaves to the roots. */ | |
7771d558 | 643 | order_pos = ipa_reduced_postorder (order, true, true, NULL); |
f7d118a9 | 644 | if (dump_file) |
7771d558 | 645 | ipa_print_order (dump_file, "reduced", order, order_pos); |
f7d118a9 | 646 | |
647 | for (i = 0; i < order_pos; i++ ) | |
648 | { | |
649 | ipa_reference_vars_info_t node_info; | |
db5a3693 | 650 | ipa_reference_global_vars_info_t node_g; |
f7d118a9 | 651 | ipa_reference_local_vars_info_t node_l; |
d2d73492 | 652 | struct cgraph_edge *e, *ie; |
48e1416a | 653 | |
f7d118a9 | 654 | bool read_all; |
655 | bool write_all; | |
656 | struct ipa_dfs_info * w_info; | |
657 | ||
658 | node = order[i]; | |
8c1fce46 | 659 | if (node->alias) |
660 | continue; | |
86844d6c | 661 | node_info = get_reference_vars_info (node); |
d2d73492 | 662 | gcc_assert (node_info); |
f7d118a9 | 663 | |
7bd95dfd | 664 | |
665 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
666 | fprintf (dump_file, "Starting cycle with %s/%i\n", | |
18841b0c | 667 | cgraph_node_asm_name (node), node->symbol.order); |
7bd95dfd | 668 | |
db5a3693 | 669 | node_l = &node_info->local; |
670 | node_g = &node_info->global; | |
f7d118a9 | 671 | |
d2d73492 | 672 | read_all = false; |
673 | write_all = false; | |
f7d118a9 | 674 | |
0a10fd82 | 675 | /* When function is overwritable, we can not assume anything. */ |
ef378c27 | 676 | if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) |
d2d73492 | 677 | read_write_all_from_decl (node, &read_all, &write_all); |
ef378c27 | 678 | |
48e1416a | 679 | for (e = node->callees; e; e = e->next_callee) |
b2c2e188 | 680 | { |
681 | enum availability avail; | |
682 | struct cgraph_node *callee = cgraph_function_node (e->callee, &avail); | |
683 | if (!callee || avail <= AVAIL_OVERWRITABLE) | |
684 | read_write_all_from_decl (callee, &read_all, &write_all); | |
685 | } | |
d2d73492 | 686 | |
687 | for (ie = node->indirect_calls; ie; ie = ie->next_callee) | |
688 | if (!(ie->indirect_info->ecf_flags & ECF_CONST)) | |
689 | { | |
690 | read_all = true; | |
7bd95dfd | 691 | if (dump_file && (dump_flags & TDF_DETAILS)) |
692 | fprintf (dump_file, " indirect call -> read all\n"); | |
d2d73492 | 693 | if (!cgraph_edge_cannot_lead_to_return (ie) |
694 | && !(ie->indirect_info->ecf_flags & ECF_PURE)) | |
7bd95dfd | 695 | { |
696 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
697 | fprintf (dump_file, " indirect call -> write all\n"); | |
698 | write_all = true; | |
699 | } | |
d2d73492 | 700 | } |
ef378c27 | 701 | |
702 | ||
d2d73492 | 703 | /* If any node in a cycle is read_all or write_all |
f7d118a9 | 704 | they all are. */ |
7d0d0ce1 | 705 | w_info = (struct ipa_dfs_info *) node->symbol.aux; |
f7d118a9 | 706 | w = w_info->next_cycle; |
d2d73492 | 707 | while (w && (!read_all || !write_all)) |
f7d118a9 | 708 | { |
7bd95dfd | 709 | if (dump_file && (dump_flags & TDF_DETAILS)) |
710 | fprintf (dump_file, " Visiting %s/%i\n", | |
18841b0c | 711 | cgraph_node_asm_name (w), w->symbol.order); |
0a10fd82 | 712 | /* When function is overwritable, we can not assume anything. */ |
ef378c27 | 713 | if (cgraph_function_body_availability (w) <= AVAIL_OVERWRITABLE) |
d2d73492 | 714 | read_write_all_from_decl (w, &read_all, &write_all); |
ef378c27 | 715 | |
48e1416a | 716 | for (e = w->callees; e; e = e->next_callee) |
b2c2e188 | 717 | { |
718 | enum availability avail; | |
719 | struct cgraph_node *callee = cgraph_function_node (e->callee, &avail); | |
720 | ||
721 | if (avail <= AVAIL_OVERWRITABLE) | |
722 | read_write_all_from_decl (callee, &read_all, &write_all); | |
723 | } | |
ef378c27 | 724 | |
d2d73492 | 725 | for (ie = w->indirect_calls; ie; ie = ie->next_callee) |
726 | if (!(ie->indirect_info->ecf_flags & ECF_CONST)) | |
727 | { | |
728 | read_all = true; | |
7bd95dfd | 729 | if (dump_file && (dump_flags & TDF_DETAILS)) |
730 | fprintf (dump_file, " indirect call -> read all\n"); | |
d2d73492 | 731 | if (!cgraph_edge_cannot_lead_to_return (ie) |
732 | && !(ie->indirect_info->ecf_flags & ECF_PURE)) | |
7bd95dfd | 733 | { |
734 | write_all = true; | |
735 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
736 | fprintf (dump_file, " indirect call -> write all\n"); | |
737 | } | |
d2d73492 | 738 | } |
f7d118a9 | 739 | |
7d0d0ce1 | 740 | w_info = (struct ipa_dfs_info *) w->symbol.aux; |
f7d118a9 | 741 | w = w_info->next_cycle; |
742 | } | |
743 | ||
ef378c27 | 744 | |
f7d118a9 | 745 | /* Initialized the bitmaps for the reduced nodes */ |
48e1416a | 746 | if (read_all) |
f7d118a9 | 747 | node_g->statics_read = all_module_statics; |
48e1416a | 748 | else |
f7d118a9 | 749 | { |
db5a3693 | 750 | node_g->statics_read = BITMAP_ALLOC (&local_info_obstack); |
48e1416a | 751 | bitmap_copy (node_g->statics_read, |
f7d118a9 | 752 | node_l->statics_read); |
753 | } | |
48e1416a | 754 | if (write_all) |
f7d118a9 | 755 | node_g->statics_written = all_module_statics; |
756 | else | |
757 | { | |
db5a3693 | 758 | node_g->statics_written = BITMAP_ALLOC (&local_info_obstack); |
48e1416a | 759 | bitmap_copy (node_g->statics_written, |
f7d118a9 | 760 | node_l->statics_written); |
761 | } | |
762 | ||
86844d6c | 763 | propagate_bits (node_g, node); |
7d0d0ce1 | 764 | w_info = (struct ipa_dfs_info *) node->symbol.aux; |
f7d118a9 | 765 | w = w_info->next_cycle; |
d2d73492 | 766 | while (w && (!read_all || !write_all)) |
f7d118a9 | 767 | { |
48e1416a | 768 | ipa_reference_vars_info_t w_ri = |
86844d6c | 769 | get_reference_vars_info (w); |
db5a3693 | 770 | ipa_reference_local_vars_info_t w_l = &w_ri->local; |
7d0d0ce1 | 771 | int flags = flags_from_decl_or_type (w->symbol.decl); |
48e1416a | 772 | |
f7d118a9 | 773 | /* These global bitmaps are initialized from the local info |
774 | of all of the nodes in the region. However there is no | |
775 | need to do any work if the bitmaps were set to | |
776 | all_module_statics. */ | |
d2d73492 | 777 | if (!read_all && !(flags & ECF_CONST)) |
f7d118a9 | 778 | bitmap_ior_into (node_g->statics_read, |
779 | w_l->statics_read); | |
d2d73492 | 780 | if (!write_all |
781 | && !(flags & ECF_PURE) | |
782 | && !cgraph_node_cannot_return (w)) | |
f7d118a9 | 783 | bitmap_ior_into (node_g->statics_written, |
784 | w_l->statics_written); | |
86844d6c | 785 | propagate_bits (node_g, w); |
7d0d0ce1 | 786 | w_info = (struct ipa_dfs_info *) w->symbol.aux; |
f7d118a9 | 787 | w = w_info->next_cycle; |
788 | } | |
789 | ||
86844d6c | 790 | /* All nodes within a cycle have the same global info bitmaps. */ |
db5a3693 | 791 | node_info->global = *node_g; |
7d0d0ce1 | 792 | w_info = (struct ipa_dfs_info *) node->symbol.aux; |
f7d118a9 | 793 | w = w_info->next_cycle; |
794 | while (w) | |
795 | { | |
48e1416a | 796 | ipa_reference_vars_info_t w_ri = |
86844d6c | 797 | get_reference_vars_info (w); |
798 | ||
db5a3693 | 799 | w_ri->global = *node_g; |
86844d6c | 800 | |
7d0d0ce1 | 801 | w_info = (struct ipa_dfs_info *) w->symbol.aux; |
f7d118a9 | 802 | w = w_info->next_cycle; |
803 | } | |
804 | } | |
805 | ||
806 | if (dump_file) | |
807 | { | |
808 | for (i = 0; i < order_pos; i++ ) | |
809 | { | |
810 | ipa_reference_vars_info_t node_info; | |
811 | ipa_reference_global_vars_info_t node_g; | |
812 | ipa_reference_local_vars_info_t node_l; | |
813 | unsigned int index; | |
814 | bitmap_iterator bi; | |
815 | struct ipa_dfs_info * w_info; | |
816 | ||
817 | node = order[i]; | |
8c1fce46 | 818 | if (node->alias) |
819 | continue; | |
86844d6c | 820 | node_info = get_reference_vars_info (node); |
db5a3693 | 821 | node_g = &node_info->global; |
822 | node_l = &node_info->local; | |
48e1416a | 823 | fprintf (dump_file, |
824 | "\nFunction name:%s/%i:", | |
18841b0c | 825 | cgraph_node_asm_name (node), node->symbol.order); |
f7d118a9 | 826 | fprintf (dump_file, "\n locals read: "); |
f589330e | 827 | if (node_l->statics_read) |
828 | EXECUTE_IF_SET_IN_BITMAP (node_l->statics_read, | |
829 | 0, index, bi) | |
830 | { | |
831 | fprintf (dump_file, "%s ", | |
832 | get_static_name (index)); | |
833 | } | |
f7d118a9 | 834 | fprintf (dump_file, "\n locals written: "); |
f589330e | 835 | if (node_l->statics_written) |
836 | EXECUTE_IF_SET_IN_BITMAP (node_l->statics_written, | |
837 | 0, index, bi) | |
838 | { | |
839 | fprintf(dump_file, "%s ", | |
840 | get_static_name (index)); | |
841 | } | |
f7d118a9 | 842 | |
7d0d0ce1 | 843 | w_info = (struct ipa_dfs_info *) node->symbol.aux; |
f7d118a9 | 844 | w = w_info->next_cycle; |
48e1416a | 845 | while (w) |
f7d118a9 | 846 | { |
48e1416a | 847 | ipa_reference_vars_info_t w_ri = |
86844d6c | 848 | get_reference_vars_info (w); |
db5a3693 | 849 | ipa_reference_local_vars_info_t w_l = &w_ri->local; |
f7d118a9 | 850 | fprintf (dump_file, "\n next cycle: %s/%i ", |
18841b0c | 851 | cgraph_node_asm_name (w), w->symbol.order); |
f565b705 | 852 | fprintf (dump_file, "\n locals read: "); |
853 | if (w_l->statics_read) | |
854 | EXECUTE_IF_SET_IN_BITMAP (w_l->statics_read, | |
855 | 0, index, bi) | |
856 | { | |
857 | fprintf (dump_file, "%s ", | |
858 | get_static_name (index)); | |
859 | } | |
f7d118a9 | 860 | |
861 | fprintf (dump_file, "\n locals written: "); | |
f565b705 | 862 | if (w_l->statics_written) |
863 | EXECUTE_IF_SET_IN_BITMAP (w_l->statics_written, | |
864 | 0, index, bi) | |
865 | { | |
866 | fprintf (dump_file, "%s ", | |
867 | get_static_name (index)); | |
868 | } | |
f7d118a9 | 869 | |
7d0d0ce1 | 870 | w_info = (struct ipa_dfs_info *) w->symbol.aux; |
f7d118a9 | 871 | w = w_info->next_cycle; |
872 | } | |
873 | fprintf (dump_file, "\n globals read: "); | |
f589330e | 874 | if (node_g->statics_read == all_module_statics) |
875 | fprintf (dump_file, "ALL"); | |
876 | else | |
877 | EXECUTE_IF_SET_IN_BITMAP (node_g->statics_read, | |
878 | 0, index, bi) | |
879 | { | |
880 | fprintf (dump_file, "%s ", | |
881 | get_static_name (index)); | |
882 | } | |
f7d118a9 | 883 | fprintf (dump_file, "\n globals written: "); |
f589330e | 884 | if (node_g->statics_written == all_module_statics) |
885 | fprintf (dump_file, "ALL"); | |
886 | else | |
887 | EXECUTE_IF_SET_IN_BITMAP (node_g->statics_written, | |
888 | 0, index, bi) | |
889 | { | |
890 | fprintf (dump_file, "%s ", | |
891 | get_static_name (index)); | |
892 | } | |
f7d118a9 | 893 | } |
894 | } | |
895 | ||
896 | /* Cleanup. */ | |
7c455d87 | 897 | FOR_EACH_DEFINED_FUNCTION (node) |
f7d118a9 | 898 | { |
899 | ipa_reference_vars_info_t node_info; | |
900 | ipa_reference_global_vars_info_t node_g; | |
db5a3693 | 901 | ipa_reference_optimization_summary_t opt; |
902 | ||
7c455d87 | 903 | if (node->alias) |
2ebf562c | 904 | continue; |
905 | ||
86844d6c | 906 | node_info = get_reference_vars_info (node); |
7bd95dfd | 907 | if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE |
7d0d0ce1 | 908 | || (flags_from_decl_or_type (node->symbol.decl) & ECF_LEAF)) |
db5a3693 | 909 | { |
910 | node_g = &node_info->global; | |
f7d118a9 | 911 | |
db5a3693 | 912 | opt = XCNEW (struct ipa_reference_optimization_summary_d); |
913 | set_reference_optimization_summary (node, opt); | |
f7d118a9 | 914 | |
db5a3693 | 915 | /* Create the complimentary sets. */ |
d2d73492 | 916 | |
917 | if (bitmap_empty_p (node_g->statics_read)) | |
918 | opt->statics_not_read = all_module_statics; | |
919 | else | |
920 | { | |
921 | opt->statics_not_read | |
922 | = BITMAP_ALLOC (&optimization_summary_obstack); | |
923 | if (node_g->statics_read != all_module_statics) | |
924 | bitmap_and_compl (opt->statics_not_read, | |
925 | all_module_statics, | |
926 | node_g->statics_read); | |
927 | } | |
928 | ||
929 | if (bitmap_empty_p (node_g->statics_written)) | |
930 | opt->statics_not_written = all_module_statics; | |
931 | else | |
932 | { | |
933 | opt->statics_not_written | |
934 | = BITMAP_ALLOC (&optimization_summary_obstack); | |
935 | if (node_g->statics_written != all_module_statics) | |
936 | bitmap_and_compl (opt->statics_not_written, | |
937 | all_module_statics, | |
938 | node_g->statics_written); | |
939 | } | |
db5a3693 | 940 | } |
dd045aee | 941 | free (node_info); |
db5a3693 | 942 | } |
943 | ||
7771d558 | 944 | ipa_free_postorder_info (); |
db5a3693 | 945 | free (order); |
48e1416a | 946 | |
ed4f5c92 | 947 | bitmap_obstack_release (&local_info_obstack); |
db5a3693 | 948 | VEC_free (ipa_reference_vars_info_t, heap, ipa_reference_vars_vector); |
949 | ipa_reference_vars_vector = NULL; | |
950 | if (dump_file) | |
951 | splay_tree_delete (reference_vars_to_consider); | |
952 | reference_vars_to_consider = NULL; | |
2a1990e9 | 953 | return 0; |
f7d118a9 | 954 | } |
955 | ||
d97be713 | 956 | /* Return true if we need to write summary of NODE. */ |
957 | ||
958 | static bool | |
959 | write_node_summary_p (struct cgraph_node *node, | |
960 | cgraph_node_set set, | |
961 | varpool_node_set vset, | |
962 | bitmap ltrans_statics) | |
963 | { | |
964 | ipa_reference_optimization_summary_t info; | |
965 | ||
966 | /* See if we have (non-empty) info. */ | |
967 | if (!node->analyzed || node->global.inlined_to) | |
968 | return false; | |
969 | info = get_reference_optimization_summary (node); | |
970 | if (!info || (bitmap_empty_p (info->statics_not_read) | |
971 | && bitmap_empty_p (info->statics_not_written))) | |
972 | return false; | |
973 | ||
974 | /* See if we want to encode it. | |
975 | Encode also referenced functions since constant folding might turn it into | |
976 | a direct call. | |
977 | ||
978 | In future we might also want to include summaries of functions references | |
979 | by initializers of constant variables references in current unit. */ | |
980 | if (!reachable_from_this_partition_p (node, set) | |
7d0d0ce1 | 981 | && !referenced_from_this_partition_p (&node->symbol.ref_list, set, vset)) |
d97be713 | 982 | return false; |
983 | ||
984 | /* See if the info has non-empty intersections with vars we want to encode. */ | |
985 | if (!bitmap_intersect_p (info->statics_not_read, ltrans_statics) | |
986 | && !bitmap_intersect_p (info->statics_not_written, ltrans_statics)) | |
987 | return false; | |
988 | return true; | |
989 | } | |
990 | ||
d2d73492 | 991 | /* Stream out BITS<RANS_STATICS as list of decls to OB. |
992 | LTRANS_STATICS_BITCOUNT specify number of bits in LTRANS_STATICS | |
993 | or -1. When it is positive, just output -1 when | |
994 | BITS<RANS_STATICS == BITS<RANS_STATICS. */ | |
d97be713 | 995 | |
996 | static void | |
997 | stream_out_bitmap (struct lto_simple_output_block *ob, | |
d2d73492 | 998 | bitmap bits, bitmap ltrans_statics, |
999 | int ltrans_statics_bitcount) | |
d97be713 | 1000 | { |
d2d73492 | 1001 | int count = 0; |
d97be713 | 1002 | unsigned int index; |
1003 | bitmap_iterator bi; | |
d2d73492 | 1004 | if (bits == all_module_statics) |
1005 | { | |
7f385784 | 1006 | streamer_write_hwi_stream (ob->main_stream, -1); |
d2d73492 | 1007 | return; |
1008 | } | |
d97be713 | 1009 | EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi) |
1010 | count ++; | |
d2d73492 | 1011 | if (count == ltrans_statics_bitcount) |
1012 | { | |
7f385784 | 1013 | streamer_write_hwi_stream (ob->main_stream, -1); |
d2d73492 | 1014 | return; |
1015 | } | |
7f385784 | 1016 | streamer_write_hwi_stream (ob->main_stream, count); |
d97be713 | 1017 | if (!count) |
1018 | return; | |
1019 | EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi) | |
1020 | { | |
1021 | tree decl = (tree)splay_tree_lookup (reference_vars_to_consider, index)->value; | |
1022 | lto_output_var_decl_index(ob->decl_state, ob->main_stream, decl); | |
1023 | } | |
1024 | } | |
1025 | ||
1026 | /* Serialize the ipa info for lto. */ | |
1027 | ||
1028 | static void | |
1029 | ipa_reference_write_optimization_summary (cgraph_node_set set, | |
1030 | varpool_node_set vset) | |
1031 | { | |
1032 | struct cgraph_node *node; | |
d97be713 | 1033 | struct lto_simple_output_block *ob |
1034 | = lto_create_simple_output_block (LTO_section_ipa_reference); | |
1035 | unsigned int count = 0; | |
d2d73492 | 1036 | int ltrans_statics_bitcount = 0; |
d97be713 | 1037 | lto_cgraph_encoder_t encoder = ob->decl_state->cgraph_node_encoder; |
d2d73492 | 1038 | lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder; |
d97be713 | 1039 | bitmap ltrans_statics = BITMAP_ALLOC (NULL); |
d2d73492 | 1040 | int i; |
d97be713 | 1041 | |
1042 | reference_vars_to_consider = splay_tree_new (splay_tree_compare_ints, 0, 0); | |
1043 | ||
1044 | /* See what variables we are interested in. */ | |
d2d73492 | 1045 | for (i = 0; i < lto_varpool_encoder_size (varpool_encoder); i++) |
1046 | { | |
1047 | struct varpool_node *vnode = lto_varpool_encoder_deref (varpool_encoder, i); | |
a7847fbd | 1048 | if (bitmap_bit_p (all_module_statics, DECL_UID (vnode->symbol.decl)) |
7d0d0ce1 | 1049 | && referenced_from_this_partition_p (&vnode->symbol.ref_list, set, vset)) |
d2d73492 | 1050 | { |
7d0d0ce1 | 1051 | tree decl = vnode->symbol.decl; |
d2d73492 | 1052 | bitmap_set_bit (ltrans_statics, DECL_UID (decl)); |
1053 | splay_tree_insert (reference_vars_to_consider, | |
1054 | DECL_UID (decl), (splay_tree_value)decl); | |
1055 | ltrans_statics_bitcount ++; | |
1056 | } | |
1057 | } | |
d97be713 | 1058 | |
d2d73492 | 1059 | |
1060 | if (ltrans_statics_bitcount) | |
1061 | for (i = 0; i < lto_cgraph_encoder_size (encoder); i++) | |
1062 | if (write_node_summary_p (lto_cgraph_encoder_deref (encoder, i), | |
1063 | set, vset, ltrans_statics)) | |
1064 | count++; | |
d97be713 | 1065 | |
7f385784 | 1066 | streamer_write_uhwi_stream (ob->main_stream, count); |
d2d73492 | 1067 | if (count) |
1068 | stream_out_bitmap (ob, ltrans_statics, ltrans_statics, | |
1069 | -1); | |
d97be713 | 1070 | |
1071 | /* Process all of the functions. */ | |
d2d73492 | 1072 | if (ltrans_statics_bitcount) |
1073 | for (i = 0; i < lto_cgraph_encoder_size (encoder); i++) | |
d97be713 | 1074 | { |
d2d73492 | 1075 | node = lto_cgraph_encoder_deref (encoder, i); |
1076 | if (write_node_summary_p (node, set, vset, ltrans_statics)) | |
1077 | { | |
1078 | ipa_reference_optimization_summary_t info; | |
1079 | int node_ref; | |
1080 | ||
1081 | info = get_reference_optimization_summary (node); | |
1082 | node_ref = lto_cgraph_encoder_encode (encoder, node); | |
7f385784 | 1083 | streamer_write_uhwi_stream (ob->main_stream, node_ref); |
d2d73492 | 1084 | |
1085 | stream_out_bitmap (ob, info->statics_not_read, ltrans_statics, | |
1086 | ltrans_statics_bitcount); | |
1087 | stream_out_bitmap (ob, info->statics_not_written, ltrans_statics, | |
1088 | ltrans_statics_bitcount); | |
1089 | } | |
d97be713 | 1090 | } |
1091 | BITMAP_FREE (ltrans_statics); | |
1092 | lto_destroy_simple_output_block (ob); | |
1093 | splay_tree_delete (reference_vars_to_consider); | |
1094 | } | |
1095 | ||
1096 | /* Deserialize the ipa info for lto. */ | |
1097 | ||
1098 | static void | |
1099 | ipa_reference_read_optimization_summary (void) | |
1100 | { | |
1101 | struct lto_file_decl_data ** file_data_vec | |
1102 | = lto_get_file_decl_data (); | |
1103 | struct lto_file_decl_data * file_data; | |
1104 | unsigned int j = 0; | |
1105 | bitmap_obstack_initialize (&optimization_summary_obstack); | |
1106 | ||
1107 | node_removal_hook_holder = | |
1108 | cgraph_add_node_removal_hook (&remove_node_data, NULL); | |
1109 | node_duplication_hook_holder = | |
1110 | cgraph_add_node_duplication_hook (&duplicate_node_data, NULL); | |
d2d73492 | 1111 | all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack); |
d97be713 | 1112 | |
1113 | while ((file_data = file_data_vec[j++])) | |
1114 | { | |
1115 | const char *data; | |
1116 | size_t len; | |
1117 | struct lto_input_block *ib | |
1118 | = lto_create_simple_input_block (file_data, | |
1119 | LTO_section_ipa_reference, | |
1120 | &data, &len); | |
1121 | if (ib) | |
1122 | { | |
1123 | unsigned int i; | |
7f385784 | 1124 | unsigned int f_count = streamer_read_uhwi (ib); |
d2d73492 | 1125 | int b_count; |
1126 | if (!f_count) | |
1127 | continue; | |
7f385784 | 1128 | b_count = streamer_read_hwi (ib); |
d2d73492 | 1129 | if (dump_file) |
1130 | fprintf (dump_file, "all module statics:"); | |
1131 | for (i = 0; i < (unsigned int)b_count; i++) | |
1132 | { | |
7f385784 | 1133 | unsigned int var_index = streamer_read_uhwi (ib); |
d2d73492 | 1134 | tree v_decl = lto_file_decl_data_get_var_decl (file_data, |
1135 | var_index); | |
1136 | bitmap_set_bit (all_module_statics, DECL_UID (v_decl)); | |
1137 | if (dump_file) | |
1138 | fprintf (dump_file, " %s", | |
1139 | lang_hooks.decl_printable_name (v_decl, 2)); | |
1140 | } | |
d97be713 | 1141 | |
1142 | for (i = 0; i < f_count; i++) | |
1143 | { | |
1144 | unsigned int j, index; | |
1145 | struct cgraph_node *node; | |
1146 | ipa_reference_optimization_summary_t info; | |
1147 | int v_count; | |
1148 | lto_cgraph_encoder_t encoder; | |
1149 | ||
7f385784 | 1150 | index = streamer_read_uhwi (ib); |
d97be713 | 1151 | encoder = file_data->cgraph_node_encoder; |
1152 | node = lto_cgraph_encoder_deref (encoder, index); | |
1153 | info = XCNEW (struct ipa_reference_optimization_summary_d); | |
1154 | set_reference_optimization_summary (node, info); | |
1155 | info->statics_not_read = BITMAP_ALLOC (&optimization_summary_obstack); | |
1156 | info->statics_not_written = BITMAP_ALLOC (&optimization_summary_obstack); | |
1157 | if (dump_file) | |
1158 | fprintf (dump_file, | |
1159 | "\nFunction name:%s/%i:\n static not read:", | |
18841b0c | 1160 | cgraph_node_asm_name (node), node->symbol.order); |
d97be713 | 1161 | |
1162 | /* Set the statics not read. */ | |
7f385784 | 1163 | v_count = streamer_read_hwi (ib); |
d2d73492 | 1164 | if (v_count == -1) |
d97be713 | 1165 | { |
d2d73492 | 1166 | info->statics_not_read = all_module_statics; |
d97be713 | 1167 | if (dump_file) |
d2d73492 | 1168 | fprintf (dump_file, " all module statics"); |
d97be713 | 1169 | } |
d2d73492 | 1170 | else |
1171 | for (j = 0; j < (unsigned int)v_count; j++) | |
1172 | { | |
7f385784 | 1173 | unsigned int var_index = streamer_read_uhwi (ib); |
d2d73492 | 1174 | tree v_decl = lto_file_decl_data_get_var_decl (file_data, |
1175 | var_index); | |
1176 | bitmap_set_bit (info->statics_not_read, DECL_UID (v_decl)); | |
1177 | if (dump_file) | |
1178 | fprintf (dump_file, " %s", | |
1179 | lang_hooks.decl_printable_name (v_decl, 2)); | |
1180 | } | |
d97be713 | 1181 | |
1182 | if (dump_file) | |
1183 | fprintf (dump_file, | |
1184 | "\n static not written:"); | |
1185 | /* Set the statics not written. */ | |
7f385784 | 1186 | v_count = streamer_read_hwi (ib); |
d2d73492 | 1187 | if (v_count == -1) |
d97be713 | 1188 | { |
d2d73492 | 1189 | info->statics_not_written = all_module_statics; |
d97be713 | 1190 | if (dump_file) |
d2d73492 | 1191 | fprintf (dump_file, " all module statics"); |
d97be713 | 1192 | } |
d2d73492 | 1193 | else |
1194 | for (j = 0; j < (unsigned int)v_count; j++) | |
1195 | { | |
7f385784 | 1196 | unsigned int var_index = streamer_read_uhwi (ib); |
d2d73492 | 1197 | tree v_decl = lto_file_decl_data_get_var_decl (file_data, |
1198 | var_index); | |
1199 | bitmap_set_bit (info->statics_not_written, DECL_UID (v_decl)); | |
1200 | if (dump_file) | |
1201 | fprintf (dump_file, " %s", | |
1202 | lang_hooks.decl_printable_name (v_decl, 2)); | |
1203 | } | |
d97be713 | 1204 | if (dump_file) |
1205 | fprintf (dump_file, "\n"); | |
1206 | } | |
1207 | ||
1208 | lto_destroy_simple_input_block (file_data, | |
1209 | LTO_section_ipa_reference, | |
1210 | ib, data, len); | |
1211 | } | |
1212 | else | |
1213 | /* Fatal error here. We do not want to support compiling ltrans units with | |
1214 | different version of compiler or different flags than the WPA unit, so | |
1215 | this should never happen. */ | |
1216 | fatal_error ("ipa reference summary is missing in ltrans unit"); | |
1217 | } | |
1218 | } | |
f7d118a9 | 1219 | |
1220 | static bool | |
1221 | gate_reference (void) | |
1222 | { | |
6329636b | 1223 | return (flag_ipa_reference |
f7d118a9 | 1224 | /* Don't bother doing anything if the program has errors. */ |
852f689e | 1225 | && !seen_error ()); |
f7d118a9 | 1226 | } |
1227 | ||
26dbec0a | 1228 | struct ipa_opt_pass_d pass_ipa_reference = |
f7d118a9 | 1229 | { |
20099e35 | 1230 | { |
cb886925 | 1231 | IPA_PASS, |
f7d118a9 | 1232 | "static-var", /* name */ |
1233 | gate_reference, /* gate */ | |
cb886925 | 1234 | propagate, /* execute */ |
f7d118a9 | 1235 | NULL, /* sub */ |
1236 | NULL, /* next */ | |
1237 | 0, /* static_pass_number */ | |
1238 | TV_IPA_REFERENCE, /* tv_id */ | |
1239 | 0, /* properties_required */ | |
1240 | 0, /* properties_provided */ | |
1241 | 0, /* properties_destroyed */ | |
1242 | 0, /* todo_flags_start */ | |
20099e35 | 1243 | 0 /* todo_flags_finish */ |
cb886925 | 1244 | }, |
f8b7e3ec | 1245 | NULL, /* generate_summary */ |
1246 | NULL, /* write_summary */ | |
1247 | NULL, /* read_summary */ | |
d97be713 | 1248 | ipa_reference_write_optimization_summary,/* write_optimization_summary */ |
1249 | ipa_reference_read_optimization_summary,/* read_optimization_summary */ | |
90464c8b | 1250 | NULL, /* stmt_fixup */ |
cb886925 | 1251 | 0, /* TODOs */ |
1252 | NULL, /* function_transform */ | |
1253 | NULL /* variable_transform */ | |
f7d118a9 | 1254 | }; |