]>
Commit | Line | Data |
---|---|---|
ea900239 | 1 | /* Callgraph based analysis of static variables. |
c75c517d SB |
2 | Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 |
3 | Free Software Foundation, Inc. | |
ea900239 DB |
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 | |
9dcd6f09 | 10 | Software Foundation; either version 3, or (at your option) any later |
ea900239 DB |
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 | |
9dcd6f09 NC |
19 | along with GCC; see the file COPYING3. If not see |
20 | <http://www.gnu.org/licenses/>. */ | |
ea900239 DB |
21 | |
22 | /* This file gathers information about how variables whose scope is | |
b8698a0f | 23 | confined to the compilation unit are used. |
ea900239 | 24 | |
4a444e58 | 25 | The transitive call site specific clobber effects are computed |
ea900239 DB |
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 | |
4a444e58 | 38 | information. */ |
ea900239 DB |
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" | |
ea264ca5 | 50 | #include "splay-tree.h" |
ea900239 DB |
51 | #include "ggc.h" |
52 | #include "ipa-utils.h" | |
53 | #include "ipa-reference.h" | |
726a989a | 54 | #include "gimple.h" |
ea900239 DB |
55 | #include "cgraph.h" |
56 | #include "output.h" | |
57 | #include "flags.h" | |
58 | #include "timevar.h" | |
59 | #include "diagnostic.h" | |
60 | #include "langhooks.h" | |
d7f09764 DN |
61 | #include "lto-streamer.h" |
62 | ||
d7f09764 DN |
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); | |
ea900239 | 68 | |
e2c9111c | 69 | /* The static variables defined within the compilation unit that are |
b8698a0f | 70 | loaded or stored directly by function that owns this structure. */ |
e2c9111c | 71 | |
b8698a0f | 72 | struct ipa_reference_local_vars_info_d |
e2c9111c JH |
73 | { |
74 | bitmap statics_read; | |
75 | bitmap statics_written; | |
76 | ||
77 | /* Set when this function calls another function external to the | |
78 | compilation unit or if the function has a asm clobber of memory. | |
79 | In general, such calls are modeled as reading and writing all | |
80 | variables (both bits on) but sometime there are attributes on the | |
81 | called function so we can do better. */ | |
82 | bool calls_read_all; | |
83 | bool calls_write_all; | |
84 | }; | |
85 | ||
86 | /* Statics that are read and written by some set of functions. The | |
87 | local ones are based on the loads and stores local to the function. | |
88 | The global ones are based on the local info as well as the | |
46c30019 | 89 | transitive closure of the functions that are called. */ |
e2c9111c JH |
90 | |
91 | struct ipa_reference_global_vars_info_d | |
92 | { | |
93 | bitmap statics_read; | |
94 | bitmap statics_written; | |
46c30019 JH |
95 | }; |
96 | ||
97 | /* Information we save about every function after ipa-reference is completted. */ | |
98 | ||
99 | struct ipa_reference_optimization_summary_d | |
100 | { | |
e2c9111c JH |
101 | bitmap statics_not_read; |
102 | bitmap statics_not_written; | |
103 | }; | |
104 | ||
105 | typedef struct ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t; | |
106 | typedef struct ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t; | |
46c30019 JH |
107 | typedef struct ipa_reference_optimization_summary_d *ipa_reference_optimization_summary_t; |
108 | ||
b8698a0f | 109 | struct ipa_reference_vars_info_d |
e2c9111c | 110 | { |
46c30019 JH |
111 | struct ipa_reference_local_vars_info_d local; |
112 | struct ipa_reference_global_vars_info_d global; | |
e2c9111c JH |
113 | }; |
114 | ||
115 | typedef struct ipa_reference_vars_info_d *ipa_reference_vars_info_t; | |
116 | ||
ea900239 | 117 | /* This splay tree contains all of the static variables that are |
46c30019 JH |
118 | being considered by the compilation level alias analysis. */ |
119 | static splay_tree reference_vars_to_consider; | |
ea900239 | 120 | |
ea900239 DB |
121 | /* A bit is set for every module static we are considering. This is |
122 | ored into the local info when asm code is found that clobbers all | |
123 | memory. */ | |
124 | static bitmap all_module_statics; | |
125 | ||
ebcf9dc8 JH |
126 | /* Obstack holding bitmaps of local analysis (live from analysis to |
127 | propagation) */ | |
128 | static bitmap_obstack local_info_obstack; | |
129 | /* Obstack holding global analysis live forever. */ | |
46c30019 | 130 | static bitmap_obstack optimization_summary_obstack; |
ea900239 | 131 | |
129a37fc | 132 | /* Holders of ipa cgraph hooks: */ |
e2c9111c JH |
133 | static struct cgraph_2node_hook_list *node_duplication_hook_holder; |
134 | static struct cgraph_node_hook_list *node_removal_hook_holder; | |
129a37fc | 135 | |
e2c9111c JH |
136 | /* Vector where the reference var infos are actually stored. */ |
137 | DEF_VEC_P (ipa_reference_vars_info_t); | |
138 | DEF_VEC_ALLOC_P (ipa_reference_vars_info_t, heap); | |
139 | static VEC (ipa_reference_vars_info_t, heap) *ipa_reference_vars_vector; | |
46c30019 JH |
140 | DEF_VEC_P (ipa_reference_optimization_summary_t); |
141 | DEF_VEC_ALLOC_P (ipa_reference_optimization_summary_t, heap); | |
142 | static VEC (ipa_reference_optimization_summary_t, heap) *ipa_reference_opt_sum_vector; | |
e2c9111c | 143 | |
ea900239 DB |
144 | /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ |
145 | static inline ipa_reference_vars_info_t | |
e2c9111c JH |
146 | get_reference_vars_info (struct cgraph_node *node) |
147 | { | |
148 | if (!ipa_reference_vars_vector | |
46c30019 JH |
149 | || VEC_length (ipa_reference_vars_info_t, |
150 | ipa_reference_vars_vector) <= (unsigned int) node->uid) | |
e2c9111c | 151 | return NULL; |
46c30019 JH |
152 | return VEC_index (ipa_reference_vars_info_t, ipa_reference_vars_vector, |
153 | node->uid); | |
e2c9111c JH |
154 | } |
155 | ||
156 | /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ | |
46c30019 JH |
157 | static inline ipa_reference_optimization_summary_t |
158 | get_reference_optimization_summary (struct cgraph_node *node) | |
ea900239 | 159 | { |
46c30019 JH |
160 | if (!ipa_reference_opt_sum_vector |
161 | || (VEC_length (ipa_reference_optimization_summary_t, | |
162 | ipa_reference_opt_sum_vector) | |
163 | <= (unsigned int) node->uid)) | |
ea900239 | 164 | return NULL; |
46c30019 JH |
165 | return VEC_index (ipa_reference_optimization_summary_t, ipa_reference_opt_sum_vector, |
166 | node->uid); | |
ea900239 DB |
167 | } |
168 | ||
46c30019 JH |
169 | /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ |
170 | static inline void | |
171 | set_reference_vars_info (struct cgraph_node *node, | |
172 | ipa_reference_vars_info_t info) | |
ea900239 | 173 | { |
46c30019 JH |
174 | if (!ipa_reference_vars_vector |
175 | || VEC_length (ipa_reference_vars_info_t, | |
176 | ipa_reference_vars_vector) <= (unsigned int) node->uid) | |
177 | VEC_safe_grow_cleared (ipa_reference_vars_info_t, heap, | |
178 | ipa_reference_vars_vector, node->uid + 1); | |
179 | VEC_replace (ipa_reference_vars_info_t, ipa_reference_vars_vector, | |
180 | node->uid, info); | |
ea900239 DB |
181 | } |
182 | ||
46c30019 JH |
183 | /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ |
184 | static inline void | |
185 | set_reference_optimization_summary (struct cgraph_node *node, | |
186 | ipa_reference_optimization_summary_t info) | |
ea900239 | 187 | { |
46c30019 JH |
188 | if (!ipa_reference_opt_sum_vector |
189 | || (VEC_length (ipa_reference_optimization_summary_t, | |
190 | ipa_reference_opt_sum_vector) | |
191 | <= (unsigned int) node->uid)) | |
192 | VEC_safe_grow_cleared (ipa_reference_optimization_summary_t, | |
193 | heap, ipa_reference_opt_sum_vector, node->uid + 1); | |
194 | VEC_replace (ipa_reference_optimization_summary_t, | |
195 | ipa_reference_opt_sum_vector, node->uid, info); | |
ea900239 DB |
196 | } |
197 | ||
198 | /* Return a bitmap indexed by_DECL_UID uid for the static variables | |
199 | that are not read during the execution of the function FN. Returns | |
200 | NULL if no data is available. */ | |
201 | ||
b8698a0f L |
202 | bitmap |
203 | ipa_reference_get_not_read_global (struct cgraph_node *fn) | |
ea900239 | 204 | { |
46c30019 JH |
205 | ipa_reference_optimization_summary_t info; |
206 | ||
207 | info = get_reference_optimization_summary (fn); | |
208 | if (info) | |
209 | return info->statics_not_read; | |
ea900239 DB |
210 | else |
211 | return NULL; | |
212 | } | |
213 | ||
214 | /* Return a bitmap indexed by DECL_UID uid for the static variables | |
215 | that are not written during the execution of the function FN. Note | |
216 | that variables written may or may not be read during the function | |
217 | call. Returns NULL if no data is available. */ | |
218 | ||
b8698a0f L |
219 | bitmap |
220 | ipa_reference_get_not_written_global (struct cgraph_node *fn) | |
ea900239 | 221 | { |
46c30019 JH |
222 | ipa_reference_optimization_summary_t info; |
223 | ||
224 | info = get_reference_optimization_summary (fn); | |
225 | if (info) | |
226 | return info->statics_not_written; | |
ea900239 DB |
227 | else |
228 | return NULL; | |
229 | } | |
230 | ||
231 | \f | |
232 | ||
233 | /* Add VAR to all_module_statics and the two | |
234 | reference_vars_to_consider* sets. */ | |
235 | ||
b8698a0f L |
236 | static inline void |
237 | add_static_var (tree var) | |
ea900239 DB |
238 | { |
239 | int uid = DECL_UID (var); | |
ebcf9dc8 | 240 | gcc_assert (TREE_CODE (var) == VAR_DECL); |
ea900239 DB |
241 | if (!bitmap_bit_p (all_module_statics, uid)) |
242 | { | |
46c30019 JH |
243 | if (dump_file) |
244 | splay_tree_insert (reference_vars_to_consider, | |
245 | uid, (splay_tree_value)var); | |
ea900239 DB |
246 | bitmap_set_bit (all_module_statics, uid); |
247 | } | |
248 | } | |
249 | ||
250 | /* Return true if the variable T is the right kind of static variable to | |
251 | perform compilation unit scope escape analysis. */ | |
252 | ||
b8698a0f | 253 | static inline bool |
5f902d76 | 254 | is_proper_for_analysis (tree t) |
ea900239 | 255 | { |
46c30019 JH |
256 | /* We handle only variables whose address is never taken. */ |
257 | if (TREE_ADDRESSABLE (t)) | |
258 | return false; | |
ea900239 DB |
259 | /* If the variable has the "used" attribute, treat it as if it had a |
260 | been touched by the devil. */ | |
b42186f1 | 261 | if (DECL_PRESERVE_P (t)) |
ea900239 DB |
262 | return false; |
263 | ||
264 | /* Do not want to do anything with volatile except mark any | |
265 | function that uses one to be not const or pure. */ | |
b8698a0f | 266 | if (TREE_THIS_VOLATILE (t)) |
ea900239 DB |
267 | return false; |
268 | ||
2276d5ed AP |
269 | /* We cannot touch decls where the type needs constructing. */ |
270 | if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (t))) | |
271 | return false; | |
272 | ||
ea900239 DB |
273 | /* This is a variable we care about. Check if we have seen it |
274 | before, and if not add it the set of variables we care about. */ | |
275 | if (!bitmap_bit_p (all_module_statics, DECL_UID (t))) | |
276 | add_static_var (t); | |
277 | ||
278 | return true; | |
279 | } | |
280 | ||
ea900239 | 281 | /* Lookup the tree node for the static variable that has UID and |
a4174ebf | 282 | convert the name to a string for debugging. */ |
ea900239 DB |
283 | |
284 | static const char * | |
285 | get_static_name (int index) | |
286 | { | |
b8698a0f | 287 | splay_tree_node stn = |
ea900239 DB |
288 | splay_tree_lookup (reference_vars_to_consider, index); |
289 | if (stn) | |
290 | return lang_hooks.decl_printable_name ((tree)(stn->value), 2); | |
291 | return NULL; | |
292 | } | |
293 | ||
e2c9111c JH |
294 | /* Or in all of the bits from every callee of X into X_GLOBAL, the caller's cycle, |
295 | bit vector. There are several cases to check to avoid the sparse | |
ea900239 DB |
296 | bitmap oring. */ |
297 | ||
298 | static void | |
e2c9111c | 299 | propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x) |
ea900239 | 300 | { |
ea900239 | 301 | struct cgraph_edge *e; |
b8698a0f | 302 | for (e = x->callees; e; e = e->next_callee) |
ea900239 DB |
303 | { |
304 | struct cgraph_node *y = e->callee; | |
305 | ||
c59f5d1b | 306 | /* Only look into nodes we can propagate something. */ |
e2c9111c | 307 | if (cgraph_function_body_availability (e->callee) > AVAIL_OVERWRITABLE) |
ea900239 | 308 | { |
e2c9111c | 309 | if (get_reference_vars_info (y)) |
ea900239 | 310 | { |
b8698a0f | 311 | ipa_reference_vars_info_t y_info |
e2c9111c | 312 | = get_reference_vars_info (y); |
46c30019 | 313 | ipa_reference_global_vars_info_t y_global = &y_info->global; |
e2c9111c JH |
314 | |
315 | /* Calls in current cycle do not have global computed yet. */ | |
46c30019 | 316 | if (!y_global->statics_read) |
e2c9111c | 317 | continue; |
b8698a0f | 318 | |
ea900239 DB |
319 | if (x_global->statics_read |
320 | != all_module_statics) | |
321 | { | |
b8698a0f | 322 | if (y_global->statics_read |
ea900239 DB |
323 | == all_module_statics) |
324 | { | |
325 | BITMAP_FREE (x_global->statics_read); | |
b8698a0f | 326 | x_global->statics_read |
ea900239 DB |
327 | = all_module_statics; |
328 | } | |
329 | /* Skip bitmaps that are pointer equal to node's bitmap | |
330 | (no reason to spin within the cycle). */ | |
b8698a0f | 331 | else if (x_global->statics_read |
ea900239 DB |
332 | != y_global->statics_read) |
333 | bitmap_ior_into (x_global->statics_read, | |
334 | y_global->statics_read); | |
335 | } | |
b8698a0f L |
336 | |
337 | if (x_global->statics_written | |
ea900239 DB |
338 | != all_module_statics) |
339 | { | |
b8698a0f | 340 | if (y_global->statics_written |
ea900239 DB |
341 | == all_module_statics) |
342 | { | |
343 | BITMAP_FREE (x_global->statics_written); | |
b8698a0f | 344 | x_global->statics_written |
ea900239 DB |
345 | = all_module_statics; |
346 | } | |
347 | /* Skip bitmaps that are pointer equal to node's bitmap | |
348 | (no reason to spin within the cycle). */ | |
b8698a0f | 349 | else if (x_global->statics_written |
ea900239 DB |
350 | != y_global->statics_written) |
351 | bitmap_ior_into (x_global->statics_written, | |
352 | y_global->statics_written); | |
353 | } | |
354 | } | |
b8698a0f | 355 | else |
ebcf9dc8 | 356 | gcc_unreachable (); |
ea900239 DB |
357 | } |
358 | } | |
359 | } | |
360 | ||
ea900239 DB |
361 | /* The init routine for analyzing global static variable usage. See |
362 | comments at top for description. */ | |
b8698a0f L |
363 | static void |
364 | ipa_init (void) | |
ea900239 | 365 | { |
d7f09764 DN |
366 | static bool init_p = false; |
367 | ||
368 | if (init_p) | |
369 | return; | |
370 | ||
371 | init_p = true; | |
372 | ||
46c30019 JH |
373 | if (dump_file) |
374 | reference_vars_to_consider = splay_tree_new (splay_tree_compare_ints, 0, 0); | |
ea900239 | 375 | |
ebcf9dc8 | 376 | bitmap_obstack_initialize (&local_info_obstack); |
46c30019 JH |
377 | bitmap_obstack_initialize (&optimization_summary_obstack); |
378 | all_module_statics = BITMAP_ALLOC (&local_info_obstack); | |
7dbca013 | 379 | |
d7f09764 DN |
380 | node_removal_hook_holder = |
381 | cgraph_add_node_removal_hook (&remove_node_data, NULL); | |
382 | node_duplication_hook_holder = | |
383 | cgraph_add_node_duplication_hook (&duplicate_node_data, NULL); | |
ea900239 DB |
384 | } |
385 | ||
d7f09764 | 386 | |
812dbce5 | 387 | /* Set up the persistent info for FN. */ |
ea900239 | 388 | |
812dbce5 JH |
389 | static ipa_reference_local_vars_info_t |
390 | init_function_info (struct cgraph_node *fn) | |
ea900239 | 391 | { |
b8698a0f | 392 | ipa_reference_vars_info_t info |
c5274326 | 393 | = XCNEW (struct ipa_reference_vars_info_d); |
ea900239 DB |
394 | |
395 | /* Add the info to the tree's annotation. */ | |
e2c9111c | 396 | set_reference_vars_info (fn, info); |
ea900239 | 397 | |
46c30019 JH |
398 | info->local.statics_read = BITMAP_ALLOC (&local_info_obstack); |
399 | info->local.statics_written = BITMAP_ALLOC (&local_info_obstack); | |
ea900239 | 400 | |
46c30019 | 401 | return &info->local; |
812dbce5 JH |
402 | } |
403 | ||
d7f09764 | 404 | |
812dbce5 JH |
405 | /* This is the main routine for finding the reference patterns for |
406 | global variables within a function FN. */ | |
d7f09764 | 407 | |
812dbce5 JH |
408 | static void |
409 | analyze_function (struct cgraph_node *fn) | |
410 | { | |
8b583a06 | 411 | ipa_reference_local_vars_info_t local; |
5f902d76 JH |
412 | struct ipa_ref *ref; |
413 | int i; | |
414 | tree var; | |
415 | struct cgraph_edge *ie; | |
812dbce5 | 416 | |
5f902d76 JH |
417 | local = init_function_info (fn); |
418 | /* Process indirect calls. All direct calles are handled at propagation | |
419 | time. */ | |
420 | for (ie = fn->indirect_calls; ie; ie = ie->next_callee) | |
421 | if (!(ie->indirect_info->ecf_flags & ECF_CONST)) | |
422 | { | |
423 | local->calls_read_all = true; | |
424 | if (!(ie->indirect_info->ecf_flags & ECF_PURE) | |
425 | && ((ie->indirect_info->ecf_flags & (ECF_NOTHROW | ECF_NORETURN)) | |
426 | != (ECF_NOTHROW | ECF_NORETURN))) | |
427 | local->calls_write_all = true; | |
428 | } | |
429 | for (i = 0; ipa_ref_list_reference_iterate (&fn->ref_list, i, ref); i++) | |
812dbce5 | 430 | { |
5f902d76 JH |
431 | if (ref->refered_type != IPA_REF_VARPOOL) |
432 | continue; | |
433 | var = ipa_ref_varpool_node (ref)->decl; | |
434 | if (ipa_ref_varpool_node (ref)->externally_visible | |
435 | || !ipa_ref_varpool_node (ref)->analyzed | |
436 | || !is_proper_for_analysis (var)) | |
437 | continue; | |
438 | switch (ref->use) | |
812dbce5 | 439 | { |
5f902d76 JH |
440 | case IPA_REF_LOAD: |
441 | bitmap_set_bit (local->statics_read, DECL_UID (var)); | |
442 | break; | |
443 | case IPA_REF_STORE: | |
444 | bitmap_set_bit (local->statics_written, DECL_UID (var)); | |
5f902d76 JH |
445 | break; |
446 | case IPA_REF_ADDR: | |
5f902d76 | 447 | break; |
812dbce5 | 448 | } |
812dbce5 | 449 | } |
ea900239 | 450 | |
5f902d76 | 451 | if ((flags_from_decl_or_type (fn->decl) & (ECF_NOTHROW | ECF_NORETURN)) |
8b583a06 JH |
452 | == (ECF_NOTHROW | ECF_NORETURN)) |
453 | { | |
454 | local->calls_write_all = false; | |
455 | bitmap_clear (local->statics_written); | |
456 | } | |
457 | ||
458 | /* Free bitmaps of direct references if we can not use them anyway. */ | |
459 | if (local->calls_write_all) | |
460 | BITMAP_FREE (local->statics_written); | |
461 | if (local->calls_read_all) | |
462 | BITMAP_FREE (local->statics_read); | |
ea900239 DB |
463 | } |
464 | ||
e2c9111c JH |
465 | static bitmap |
466 | copy_global_bitmap (bitmap src) | |
467 | { | |
468 | bitmap dst; | |
469 | if (!src) | |
470 | return NULL; | |
46c30019 | 471 | dst = BITMAP_ALLOC (&optimization_summary_obstack); |
e2c9111c JH |
472 | bitmap_copy (dst, src); |
473 | return dst; | |
474 | } | |
475 | ||
5f902d76 | 476 | |
e2c9111c JH |
477 | /* Called when new clone is inserted to callgraph late. */ |
478 | ||
479 | static void | |
480 | duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst, | |
481 | void *data ATTRIBUTE_UNUSED) | |
482 | { | |
46c30019 JH |
483 | ipa_reference_optimization_summary_t ginfo; |
484 | ipa_reference_optimization_summary_t dst_ginfo; | |
e2c9111c | 485 | |
46c30019 | 486 | ginfo = get_reference_optimization_summary (src); |
5f902d76 | 487 | if (!ginfo) |
e2c9111c | 488 | return; |
46c30019 JH |
489 | dst_ginfo = XCNEW (struct ipa_reference_optimization_summary_d); |
490 | set_reference_optimization_summary (dst, dst_ginfo); | |
491 | dst_ginfo->statics_not_read = copy_global_bitmap (ginfo->statics_not_read); | |
492 | dst_ginfo->statics_not_written = copy_global_bitmap (ginfo->statics_not_written); | |
e2c9111c JH |
493 | } |
494 | ||
495 | /* Called when node is removed. */ | |
496 | ||
497 | static void | |
498 | remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) | |
499 | { | |
46c30019 JH |
500 | ipa_reference_optimization_summary_t ginfo; |
501 | ginfo = get_reference_optimization_summary (node); | |
502 | if (ginfo) | |
503 | { | |
504 | if (ginfo->statics_not_read | |
505 | && ginfo->statics_not_read != all_module_statics) | |
506 | BITMAP_FREE (ginfo->statics_not_read); | |
507 | ||
508 | if (ginfo->statics_not_written | |
509 | && ginfo->statics_not_written != all_module_statics) | |
510 | BITMAP_FREE (ginfo->statics_not_written); | |
511 | free (ginfo); | |
512 | set_reference_optimization_summary (node, NULL); | |
513 | } | |
e2c9111c JH |
514 | } |
515 | ||
812dbce5 JH |
516 | /* Analyze each function in the cgraph to see which global or statics |
517 | are read or written. */ | |
518 | ||
b8698a0f | 519 | static void |
812dbce5 | 520 | generate_summary (void) |
ea900239 DB |
521 | { |
522 | struct cgraph_node *node; | |
812dbce5 JH |
523 | unsigned int index; |
524 | bitmap_iterator bi; | |
812dbce5 | 525 | bitmap bm_temp; |
b8698a0f | 526 | |
ea900239 | 527 | ipa_init (); |
ebcf9dc8 | 528 | bm_temp = BITMAP_ALLOC (&local_info_obstack); |
ea900239 | 529 | |
5f902d76 | 530 | /* Process all of the functions next. */ |
ea900239 | 531 | for (node = cgraph_nodes; node; node = node->next) |
5f902d76 | 532 | if (node->analyzed) |
ea900239 DB |
533 | analyze_function (node); |
534 | ||
812dbce5 | 535 | if (dump_file) |
ea900239 DB |
536 | EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi) |
537 | { | |
812dbce5 JH |
538 | fprintf (dump_file, "\nPromotable global:%s", |
539 | get_static_name (index)); | |
ea900239 | 540 | } |
b8698a0f | 541 | |
812dbce5 | 542 | BITMAP_FREE(bm_temp); |
b8698a0f | 543 | |
ea900239 | 544 | if (dump_file) |
812dbce5 | 545 | for (node = cgraph_nodes; node; node = node->next) |
e2c9111c | 546 | if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) |
ea900239 | 547 | { |
ea900239 | 548 | ipa_reference_local_vars_info_t l; |
812dbce5 | 549 | unsigned int index; |
ea900239 | 550 | bitmap_iterator bi; |
b8698a0f | 551 | |
46c30019 | 552 | l = &get_reference_vars_info (node)->local; |
b8698a0f L |
553 | fprintf (dump_file, |
554 | "\nFunction name:%s/%i:", | |
ea900239 DB |
555 | cgraph_node_name (node), node->uid); |
556 | fprintf (dump_file, "\n locals read: "); | |
8b583a06 JH |
557 | if (l->statics_read) |
558 | EXECUTE_IF_SET_IN_BITMAP (l->statics_read, | |
559 | 0, index, bi) | |
560 | { | |
561 | fprintf (dump_file, "%s ", | |
562 | get_static_name (index)); | |
563 | } | |
ea900239 | 564 | fprintf (dump_file, "\n locals written: "); |
8b583a06 JH |
565 | if (l->statics_written) |
566 | EXECUTE_IF_SET_IN_BITMAP (l->statics_written, | |
567 | 0, index, bi) | |
568 | { | |
569 | fprintf(dump_file, "%s ", | |
570 | get_static_name (index)); | |
571 | } | |
e2c9111c JH |
572 | if (l->calls_read_all) |
573 | fprintf (dump_file, "\n calls read all: "); | |
574 | if (l->calls_write_all) | |
575 | fprintf (dump_file, "\n calls read all: "); | |
ea900239 | 576 | } |
812dbce5 JH |
577 | } |
578 | \f | |
c59f5d1b | 579 | /* Set READ_ALL/WRITE_ALL based on DECL flags. */ |
46c30019 | 580 | |
c59f5d1b JH |
581 | static void |
582 | read_write_all_from_decl (tree decl, bool * read_all, bool * write_all) | |
583 | { | |
584 | int flags = flags_from_decl_or_type (decl); | |
585 | if (flags & ECF_CONST) | |
586 | ; | |
587 | else if (flags & ECF_PURE) | |
588 | *read_all = true; | |
589 | else | |
590 | { | |
591 | /* TODO: To be able to produce sane results, we should also handle | |
46c30019 | 592 | common builtins, in particular throw. */ |
c59f5d1b | 593 | *read_all = true; |
46c30019 | 594 | /* When function does not return, it is safe to ignore anythign it writes |
8b583a06 JH |
595 | to, because the effect will never happen. */ |
596 | if ((flags & (ECF_NOTHROW | ECF_NORETURN)) | |
597 | != (ECF_NOTHROW | ECF_NORETURN)) | |
598 | *write_all = true; | |
c59f5d1b JH |
599 | } |
600 | } | |
601 | ||
812dbce5 | 602 | /* Produce the global information by preforming a transitive closure |
46c30019 | 603 | on the local information that was produced by ipa_analyze_function */ |
812dbce5 JH |
604 | |
605 | static unsigned int | |
606 | propagate (void) | |
607 | { | |
608 | struct cgraph_node *node; | |
609 | struct cgraph_node *w; | |
610 | struct cgraph_node **order = | |
611 | XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); | |
2505c5ed | 612 | int order_pos = ipa_utils_reduced_inorder (order, false, true, NULL); |
812dbce5 JH |
613 | int i; |
614 | ||
b8698a0f | 615 | if (dump_file) |
812dbce5 | 616 | dump_cgraph (dump_file); |
ea900239 | 617 | |
46c30019 | 618 | ipa_discover_readonly_nonaddressable_vars (); |
5f902d76 JH |
619 | generate_summary (); |
620 | ||
ea900239 DB |
621 | /* Propagate the local information thru the call graph to produce |
622 | the global information. All the nodes within a cycle will have | |
623 | the same info so we collapse cycles first. Then we can do the | |
624 | propagation in one pass from the leaves to the roots. */ | |
2505c5ed | 625 | order_pos = ipa_utils_reduced_inorder (order, true, true, NULL); |
ea900239 DB |
626 | if (dump_file) |
627 | ipa_utils_print_order(dump_file, "reduced", order, order_pos); | |
628 | ||
629 | for (i = 0; i < order_pos; i++ ) | |
630 | { | |
631 | ipa_reference_vars_info_t node_info; | |
46c30019 | 632 | ipa_reference_global_vars_info_t node_g; |
ea900239 | 633 | ipa_reference_local_vars_info_t node_l; |
c59f5d1b | 634 | struct cgraph_edge *e; |
b8698a0f | 635 | |
ea900239 DB |
636 | bool read_all; |
637 | bool write_all; | |
638 | struct ipa_dfs_info * w_info; | |
639 | ||
640 | node = order[i]; | |
e2c9111c | 641 | node_info = get_reference_vars_info (node); |
b8698a0f | 642 | if (!node_info) |
ea900239 DB |
643 | { |
644 | dump_cgraph_node (stderr, node); | |
645 | dump_cgraph (stderr); | |
646 | gcc_unreachable (); | |
647 | } | |
648 | ||
46c30019 JH |
649 | node_l = &node_info->local; |
650 | node_g = &node_info->global; | |
ea900239 DB |
651 | |
652 | read_all = node_l->calls_read_all; | |
653 | write_all = node_l->calls_write_all; | |
654 | ||
c59f5d1b JH |
655 | /* When function is overwrittable, we can not assume anything. */ |
656 | if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) | |
657 | read_write_all_from_decl (node->decl, &read_all, &write_all); | |
658 | ||
b8698a0f | 659 | for (e = node->callees; e; e = e->next_callee) |
c59f5d1b JH |
660 | if (cgraph_function_body_availability (e->callee) <= AVAIL_OVERWRITABLE) |
661 | read_write_all_from_decl (e->callee->decl, &read_all, &write_all); | |
662 | ||
663 | ||
ea900239 DB |
664 | /* If any node in a cycle is calls_read_all or calls_write_all |
665 | they all are. */ | |
c5274326 | 666 | w_info = (struct ipa_dfs_info *) node->aux; |
ea900239 DB |
667 | w = w_info->next_cycle; |
668 | while (w) | |
669 | { | |
b8698a0f | 670 | ipa_reference_local_vars_info_t w_l = |
46c30019 | 671 | &get_reference_vars_info (w)->local; |
c59f5d1b JH |
672 | |
673 | /* When function is overwrittable, we can not assume anything. */ | |
674 | if (cgraph_function_body_availability (w) <= AVAIL_OVERWRITABLE) | |
675 | read_write_all_from_decl (w->decl, &read_all, &write_all); | |
676 | ||
b8698a0f | 677 | for (e = w->callees; e; e = e->next_callee) |
c59f5d1b JH |
678 | if (cgraph_function_body_availability (e->callee) <= AVAIL_OVERWRITABLE) |
679 | read_write_all_from_decl (e->callee->decl, &read_all, &write_all); | |
680 | ||
ea900239 DB |
681 | read_all |= w_l->calls_read_all; |
682 | write_all |= w_l->calls_write_all; | |
683 | ||
c5274326 | 684 | w_info = (struct ipa_dfs_info *) w->aux; |
ea900239 DB |
685 | w = w_info->next_cycle; |
686 | } | |
687 | ||
c59f5d1b | 688 | |
ea900239 | 689 | /* Initialized the bitmaps for the reduced nodes */ |
b8698a0f | 690 | if (read_all) |
ea900239 | 691 | node_g->statics_read = all_module_statics; |
b8698a0f | 692 | else |
ea900239 | 693 | { |
46c30019 | 694 | node_g->statics_read = BITMAP_ALLOC (&local_info_obstack); |
b8698a0f | 695 | bitmap_copy (node_g->statics_read, |
ea900239 DB |
696 | node_l->statics_read); |
697 | } | |
b8698a0f | 698 | if (write_all) |
ea900239 DB |
699 | node_g->statics_written = all_module_statics; |
700 | else | |
701 | { | |
46c30019 | 702 | node_g->statics_written = BITMAP_ALLOC (&local_info_obstack); |
b8698a0f | 703 | bitmap_copy (node_g->statics_written, |
ea900239 DB |
704 | node_l->statics_written); |
705 | } | |
706 | ||
e2c9111c | 707 | propagate_bits (node_g, node); |
c5274326 | 708 | w_info = (struct ipa_dfs_info *) node->aux; |
ea900239 DB |
709 | w = w_info->next_cycle; |
710 | while (w) | |
711 | { | |
b8698a0f | 712 | ipa_reference_vars_info_t w_ri = |
e2c9111c | 713 | get_reference_vars_info (w); |
46c30019 | 714 | ipa_reference_local_vars_info_t w_l = &w_ri->local; |
b8698a0f | 715 | |
ea900239 DB |
716 | /* These global bitmaps are initialized from the local info |
717 | of all of the nodes in the region. However there is no | |
718 | need to do any work if the bitmaps were set to | |
719 | all_module_statics. */ | |
720 | if (!read_all) | |
721 | bitmap_ior_into (node_g->statics_read, | |
722 | w_l->statics_read); | |
723 | if (!write_all) | |
724 | bitmap_ior_into (node_g->statics_written, | |
725 | w_l->statics_written); | |
e2c9111c | 726 | propagate_bits (node_g, w); |
c5274326 | 727 | w_info = (struct ipa_dfs_info *) w->aux; |
ea900239 DB |
728 | w = w_info->next_cycle; |
729 | } | |
730 | ||
e2c9111c | 731 | /* All nodes within a cycle have the same global info bitmaps. */ |
46c30019 | 732 | node_info->global = *node_g; |
c5274326 | 733 | w_info = (struct ipa_dfs_info *) node->aux; |
ea900239 DB |
734 | w = w_info->next_cycle; |
735 | while (w) | |
736 | { | |
b8698a0f | 737 | ipa_reference_vars_info_t w_ri = |
e2c9111c JH |
738 | get_reference_vars_info (w); |
739 | ||
46c30019 | 740 | w_ri->global = *node_g; |
e2c9111c | 741 | |
c5274326 | 742 | w_info = (struct ipa_dfs_info *) w->aux; |
ea900239 DB |
743 | w = w_info->next_cycle; |
744 | } | |
745 | } | |
746 | ||
747 | if (dump_file) | |
748 | { | |
749 | for (i = 0; i < order_pos; i++ ) | |
750 | { | |
751 | ipa_reference_vars_info_t node_info; | |
752 | ipa_reference_global_vars_info_t node_g; | |
753 | ipa_reference_local_vars_info_t node_l; | |
754 | unsigned int index; | |
755 | bitmap_iterator bi; | |
756 | struct ipa_dfs_info * w_info; | |
757 | ||
758 | node = order[i]; | |
e2c9111c | 759 | node_info = get_reference_vars_info (node); |
46c30019 JH |
760 | node_g = &node_info->global; |
761 | node_l = &node_info->local; | |
b8698a0f L |
762 | fprintf (dump_file, |
763 | "\nFunction name:%s/%i:", | |
ea900239 DB |
764 | cgraph_node_name (node), node->uid); |
765 | fprintf (dump_file, "\n locals read: "); | |
8b583a06 JH |
766 | if (node_l->statics_read) |
767 | EXECUTE_IF_SET_IN_BITMAP (node_l->statics_read, | |
768 | 0, index, bi) | |
769 | { | |
770 | fprintf (dump_file, "%s ", | |
771 | get_static_name (index)); | |
772 | } | |
ea900239 | 773 | fprintf (dump_file, "\n locals written: "); |
8b583a06 JH |
774 | if (node_l->statics_written) |
775 | EXECUTE_IF_SET_IN_BITMAP (node_l->statics_written, | |
776 | 0, index, bi) | |
777 | { | |
778 | fprintf(dump_file, "%s ", | |
779 | get_static_name (index)); | |
780 | } | |
ea900239 | 781 | |
c5274326 | 782 | w_info = (struct ipa_dfs_info *) node->aux; |
ea900239 | 783 | w = w_info->next_cycle; |
b8698a0f | 784 | while (w) |
ea900239 | 785 | { |
b8698a0f | 786 | ipa_reference_vars_info_t w_ri = |
e2c9111c | 787 | get_reference_vars_info (w); |
46c30019 | 788 | ipa_reference_local_vars_info_t w_l = &w_ri->local; |
ea900239 DB |
789 | fprintf (dump_file, "\n next cycle: %s/%i ", |
790 | cgraph_node_name (w), w->uid); | |
40513dd3 JJ |
791 | fprintf (dump_file, "\n locals read: "); |
792 | if (w_l->statics_read) | |
793 | EXECUTE_IF_SET_IN_BITMAP (w_l->statics_read, | |
794 | 0, index, bi) | |
795 | { | |
796 | fprintf (dump_file, "%s ", | |
797 | get_static_name (index)); | |
798 | } | |
ea900239 DB |
799 | |
800 | fprintf (dump_file, "\n locals written: "); | |
40513dd3 JJ |
801 | if (w_l->statics_written) |
802 | EXECUTE_IF_SET_IN_BITMAP (w_l->statics_written, | |
803 | 0, index, bi) | |
804 | { | |
805 | fprintf (dump_file, "%s ", | |
806 | get_static_name (index)); | |
807 | } | |
ea900239 | 808 | |
c5274326 | 809 | w_info = (struct ipa_dfs_info *) w->aux; |
ea900239 DB |
810 | w = w_info->next_cycle; |
811 | } | |
812 | fprintf (dump_file, "\n globals read: "); | |
8b583a06 JH |
813 | if (node_g->statics_read == all_module_statics) |
814 | fprintf (dump_file, "ALL"); | |
815 | else | |
816 | EXECUTE_IF_SET_IN_BITMAP (node_g->statics_read, | |
817 | 0, index, bi) | |
818 | { | |
819 | fprintf (dump_file, "%s ", | |
820 | get_static_name (index)); | |
821 | } | |
ea900239 | 822 | fprintf (dump_file, "\n globals written: "); |
8b583a06 JH |
823 | if (node_g->statics_written == all_module_statics) |
824 | fprintf (dump_file, "ALL"); | |
825 | else | |
826 | EXECUTE_IF_SET_IN_BITMAP (node_g->statics_written, | |
827 | 0, index, bi) | |
828 | { | |
829 | fprintf (dump_file, "%s ", | |
830 | get_static_name (index)); | |
831 | } | |
ea900239 DB |
832 | } |
833 | } | |
834 | ||
835 | /* Cleanup. */ | |
836 | for (i = 0; i < order_pos; i++ ) | |
837 | { | |
838 | ipa_reference_vars_info_t node_info; | |
839 | ipa_reference_global_vars_info_t node_g; | |
46c30019 JH |
840 | ipa_reference_optimization_summary_t opt; |
841 | ||
ea900239 | 842 | node = order[i]; |
e2c9111c | 843 | node_info = get_reference_vars_info (node); |
46c30019 JH |
844 | if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE) |
845 | { | |
846 | node_g = &node_info->global; | |
ea900239 | 847 | |
46c30019 JH |
848 | opt = XCNEW (struct ipa_reference_optimization_summary_d); |
849 | set_reference_optimization_summary (node, opt); | |
ea900239 | 850 | |
46c30019 JH |
851 | /* Create the complimentary sets. */ |
852 | opt->statics_not_read = BITMAP_ALLOC (&optimization_summary_obstack); | |
853 | opt->statics_not_written = BITMAP_ALLOC (&optimization_summary_obstack); | |
854 | ||
855 | if (node_g->statics_read != all_module_statics) | |
856 | bitmap_and_compl (opt->statics_not_read, | |
857 | all_module_statics, | |
858 | node_g->statics_read); | |
b8698a0f | 859 | |
46c30019 JH |
860 | if (node_g->statics_written |
861 | != all_module_statics) | |
862 | bitmap_and_compl (opt->statics_not_written, | |
863 | all_module_statics, | |
864 | node_g->statics_written); | |
865 | } | |
866 | if (node_info) | |
867 | free (node_info); | |
ea900239 DB |
868 | if (node->aux) |
869 | { | |
870 | free (node->aux); | |
871 | node->aux = NULL; | |
872 | } | |
46c30019 JH |
873 | } |
874 | ||
875 | free (order); | |
b8698a0f | 876 | |
ebcf9dc8 | 877 | bitmap_obstack_release (&local_info_obstack); |
46c30019 JH |
878 | VEC_free (ipa_reference_vars_info_t, heap, ipa_reference_vars_vector); |
879 | ipa_reference_vars_vector = NULL; | |
880 | if (dump_file) | |
881 | splay_tree_delete (reference_vars_to_consider); | |
882 | reference_vars_to_consider = NULL; | |
883 | all_module_statics = NULL; | |
c2924966 | 884 | return 0; |
ea900239 DB |
885 | } |
886 | ||
887 | ||
888 | static bool | |
889 | gate_reference (void) | |
890 | { | |
7e8b322a | 891 | return (flag_ipa_reference |
ea900239 DB |
892 | /* Don't bother doing anything if the program has errors. */ |
893 | && !(errorcount || sorrycount)); | |
894 | } | |
895 | ||
7e5487a2 | 896 | struct ipa_opt_pass_d pass_ipa_reference = |
ea900239 | 897 | { |
8ddbbcae | 898 | { |
812dbce5 | 899 | IPA_PASS, |
ea900239 DB |
900 | "static-var", /* name */ |
901 | gate_reference, /* gate */ | |
812dbce5 | 902 | propagate, /* execute */ |
ea900239 DB |
903 | NULL, /* sub */ |
904 | NULL, /* next */ | |
905 | 0, /* static_pass_number */ | |
906 | TV_IPA_REFERENCE, /* tv_id */ | |
907 | 0, /* properties_required */ | |
908 | 0, /* properties_provided */ | |
909 | 0, /* properties_destroyed */ | |
910 | 0, /* todo_flags_start */ | |
8ddbbcae | 911 | 0 /* todo_flags_finish */ |
812dbce5 | 912 | }, |
5f902d76 JH |
913 | NULL, /* generate_summary */ |
914 | NULL, /* write_summary */ | |
915 | NULL, /* read_summary */ | |
e792884f JH |
916 | NULL, /* write_optimization_summary */ |
917 | NULL, /* read_optimization_summary */ | |
2c5721d9 | 918 | NULL, /* stmt_fixup */ |
812dbce5 JH |
919 | 0, /* TODOs */ |
920 | NULL, /* function_transform */ | |
921 | NULL /* variable_transform */ | |
ea900239 | 922 | }; |