Mercurial > hg > CbC > CbC_gcc
comparison gcc/ipa-reference.c @ 0:a06113de4d67
first commit
author | kent <kent@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2009 14:47:48 +0900 |
parents | |
children | 77e2b8dfacca |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a06113de4d67 |
---|---|
1 /* Callgraph based analysis of static variables. | |
2 Copyright (C) 2004, 2005, 2007, 2008 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 There are two categories of information produced by this pass: | |
25 | |
26 1) The addressable (TREE_ADDRESSABLE) bit and readonly | |
27 (TREE_READONLY) bit associated with these variables is properly set | |
28 based on scanning all of the code withing the compilation unit. | |
29 | |
30 2) The transitive call site specific clobber effects are computed | |
31 for the variables whose scope is contained within this compilation | |
32 unit. | |
33 | |
34 First each function and static variable initialization is analyzed | |
35 to determine which local static variables are either read, written, | |
36 or have their address taken. Any local static that has its address | |
37 taken is removed from consideration. Once the local read and | |
38 writes are determined, a transitive closure of this information is | |
39 performed over the call graph to determine the worst case set of | |
40 side effects of each call. In later parts of the compiler, these | |
41 local and global sets are examined to make the call clobbering less | |
42 traumatic, promote some statics to registers, and improve aliasing | |
43 information. | |
44 | |
45 Currently must be run after inlining decisions have been made since | |
46 otherwise, the local sets will not contain information that is | |
47 consistent with post inlined state. The global sets are not prone | |
48 to this problem since they are by definition transitive. */ | |
49 | |
50 #include "config.h" | |
51 #include "system.h" | |
52 #include "coretypes.h" | |
53 #include "tm.h" | |
54 #include "tree.h" | |
55 #include "tree-flow.h" | |
56 #include "tree-inline.h" | |
57 #include "tree-pass.h" | |
58 #include "langhooks.h" | |
59 #include "pointer-set.h" | |
60 #include "ggc.h" | |
61 #include "ipa-utils.h" | |
62 #include "ipa-reference.h" | |
63 #include "c-common.h" | |
64 #include "gimple.h" | |
65 #include "cgraph.h" | |
66 #include "output.h" | |
67 #include "flags.h" | |
68 #include "timevar.h" | |
69 #include "diagnostic.h" | |
70 #include "langhooks.h" | |
71 | |
72 /* The static variables defined within the compilation unit that are | |
73 loaded or stored directly by function that owns this structure. */ | |
74 | |
75 struct ipa_reference_local_vars_info_d | |
76 { | |
77 bitmap statics_read; | |
78 bitmap statics_written; | |
79 | |
80 /* Set when this function calls another function external to the | |
81 compilation unit or if the function has a asm clobber of memory. | |
82 In general, such calls are modeled as reading and writing all | |
83 variables (both bits on) but sometime there are attributes on the | |
84 called function so we can do better. */ | |
85 bool calls_read_all; | |
86 bool calls_write_all; | |
87 }; | |
88 | |
89 /* Statics that are read and written by some set of functions. The | |
90 local ones are based on the loads and stores local to the function. | |
91 The global ones are based on the local info as well as the | |
92 transitive closure of the functions that are called. The | |
93 structures are separated to allow the global structures to be | |
94 shared between several functions since every function within a | |
95 strongly connected component will have the same information. This | |
96 sharing saves both time and space in the computation of the vectors | |
97 as well as their translation from decl_uid form to ann_uid | |
98 form. */ | |
99 | |
100 struct ipa_reference_global_vars_info_d | |
101 { | |
102 bitmap statics_read; | |
103 bitmap statics_written; | |
104 bitmap statics_not_read; | |
105 bitmap statics_not_written; | |
106 }; | |
107 | |
108 typedef struct ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t; | |
109 typedef struct ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t; | |
110 struct ipa_reference_vars_info_d | |
111 { | |
112 ipa_reference_local_vars_info_t local; | |
113 ipa_reference_global_vars_info_t global; | |
114 }; | |
115 | |
116 typedef struct ipa_reference_vars_info_d *ipa_reference_vars_info_t; | |
117 | |
118 /* This splay tree contains all of the static variables that are | |
119 being considered by the compilation level alias analysis. For | |
120 module_at_a_time compilation, this is the set of static but not | |
121 public variables. Any variables that either have their address | |
122 taken or participate in otherwise unsavory operations are deleted | |
123 from this list. */ | |
124 static GTY((param1_is(int), param2_is(tree))) | |
125 splay_tree reference_vars_to_consider; | |
126 | |
127 /* This bitmap is used to knock out the module static variables whose | |
128 addresses have been taken and passed around. */ | |
129 static bitmap module_statics_escape; | |
130 | |
131 /* This bitmap is used to knock out the module static variables that | |
132 are not readonly. */ | |
133 static bitmap module_statics_written; | |
134 | |
135 /* A bit is set for every module static we are considering. This is | |
136 ored into the local info when asm code is found that clobbers all | |
137 memory. */ | |
138 static bitmap all_module_statics; | |
139 | |
140 static struct pointer_set_t *visited_nodes; | |
141 | |
142 /* Obstack holding bitmaps of local analysis (live from analysis to | |
143 propagation) */ | |
144 static bitmap_obstack local_info_obstack; | |
145 /* Obstack holding global analysis live forever. */ | |
146 static bitmap_obstack global_info_obstack; | |
147 | |
148 /* Holders of ipa cgraph hooks: */ | |
149 static struct cgraph_node_hook_list *function_insertion_hook_holder; | |
150 static struct cgraph_2node_hook_list *node_duplication_hook_holder; | |
151 static struct cgraph_node_hook_list *node_removal_hook_holder; | |
152 | |
153 enum initialization_status_t | |
154 { | |
155 UNINITIALIZED, | |
156 RUNNING, | |
157 FINISHED | |
158 }; | |
159 | |
160 tree memory_identifier_string; | |
161 | |
162 /* Vector where the reference var infos are actually stored. */ | |
163 DEF_VEC_P (ipa_reference_vars_info_t); | |
164 DEF_VEC_ALLOC_P (ipa_reference_vars_info_t, heap); | |
165 static VEC (ipa_reference_vars_info_t, heap) *ipa_reference_vars_vector; | |
166 | |
167 /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ | |
168 static inline ipa_reference_vars_info_t | |
169 get_reference_vars_info (struct cgraph_node *node) | |
170 { | |
171 if (!ipa_reference_vars_vector | |
172 || VEC_length (ipa_reference_vars_info_t, ipa_reference_vars_vector) <= (unsigned int)node->uid) | |
173 return NULL; | |
174 return VEC_index (ipa_reference_vars_info_t, ipa_reference_vars_vector, node->uid); | |
175 } | |
176 | |
177 /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ | |
178 static inline void | |
179 set_reference_vars_info (struct cgraph_node *node, ipa_reference_vars_info_t info) | |
180 { | |
181 if (!ipa_reference_vars_vector | |
182 || VEC_length (ipa_reference_vars_info_t, ipa_reference_vars_vector) <= (unsigned int)node->uid) | |
183 VEC_safe_grow_cleared (ipa_reference_vars_info_t, heap, ipa_reference_vars_vector, node->uid + 1); | |
184 VEC_replace (ipa_reference_vars_info_t, ipa_reference_vars_vector, node->uid, info); | |
185 } | |
186 | |
187 /* Get a bitmap that contains all of the locally referenced static | |
188 variables for function FN. */ | |
189 static ipa_reference_local_vars_info_t | |
190 get_local_reference_vars_info (struct cgraph_node *fn) | |
191 { | |
192 ipa_reference_vars_info_t info = get_reference_vars_info (fn); | |
193 | |
194 if (info) | |
195 return info->local; | |
196 else | |
197 /* This phase was not run. */ | |
198 return NULL; | |
199 } | |
200 | |
201 /* Get a bitmap that contains all of the globally referenced static | |
202 variables for function FN. */ | |
203 | |
204 static ipa_reference_global_vars_info_t | |
205 get_global_reference_vars_info (struct cgraph_node *fn) | |
206 { | |
207 ipa_reference_vars_info_t info = get_reference_vars_info (fn); | |
208 | |
209 if (info) | |
210 return info->global; | |
211 else | |
212 /* This phase was not run. */ | |
213 return NULL; | |
214 } | |
215 | |
216 /* Return a bitmap indexed by VAR_DECL uid for the static variables | |
217 that are read during the execution of the function FN. Returns | |
218 NULL if no data is available. */ | |
219 | |
220 bitmap | |
221 ipa_reference_get_read_global (struct cgraph_node *fn) | |
222 { | |
223 ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn); | |
224 if (g) | |
225 return g->statics_read; | |
226 else | |
227 return NULL; | |
228 } | |
229 | |
230 /* Return a bitmap indexed by VAR_DECL uid for the static variables | |
231 that are written during the execution of the function FN. Note | |
232 that variables written may or may not be read during the function | |
233 call. Returns NULL if no data is available. */ | |
234 | |
235 bitmap | |
236 ipa_reference_get_written_global (struct cgraph_node *fn) | |
237 { | |
238 ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn); | |
239 if (g) | |
240 return g->statics_written; | |
241 else | |
242 return NULL; | |
243 } | |
244 | |
245 /* Return a bitmap indexed by_DECL_UID uid for the static variables | |
246 that are not read during the execution of the function FN. Returns | |
247 NULL if no data is available. */ | |
248 | |
249 bitmap | |
250 ipa_reference_get_not_read_global (struct cgraph_node *fn) | |
251 { | |
252 ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn); | |
253 if (g) | |
254 return g->statics_not_read; | |
255 else | |
256 return NULL; | |
257 } | |
258 | |
259 /* Return a bitmap indexed by DECL_UID uid for the static variables | |
260 that are not written during the execution of the function FN. Note | |
261 that variables written may or may not be read during the function | |
262 call. Returns NULL if no data is available. */ | |
263 | |
264 bitmap | |
265 ipa_reference_get_not_written_global (struct cgraph_node *fn) | |
266 { | |
267 ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn); | |
268 if (g) | |
269 return g->statics_not_written; | |
270 else | |
271 return NULL; | |
272 } | |
273 | |
274 | |
275 | |
276 /* Add VAR to all_module_statics and the two | |
277 reference_vars_to_consider* sets. */ | |
278 | |
279 static inline void | |
280 add_static_var (tree var) | |
281 { | |
282 int uid = DECL_UID (var); | |
283 gcc_assert (TREE_CODE (var) == VAR_DECL); | |
284 if (!bitmap_bit_p (all_module_statics, uid)) | |
285 { | |
286 splay_tree_insert (reference_vars_to_consider, | |
287 uid, (splay_tree_value)var); | |
288 bitmap_set_bit (all_module_statics, uid); | |
289 } | |
290 } | |
291 | |
292 /* Return true if the variable T is the right kind of static variable to | |
293 perform compilation unit scope escape analysis. */ | |
294 | |
295 static inline bool | |
296 has_proper_scope_for_analysis (tree t) | |
297 { | |
298 /* If the variable has the "used" attribute, treat it as if it had a | |
299 been touched by the devil. */ | |
300 if (lookup_attribute ("used", DECL_ATTRIBUTES (t))) | |
301 return false; | |
302 | |
303 /* Do not want to do anything with volatile except mark any | |
304 function that uses one to be not const or pure. */ | |
305 if (TREE_THIS_VOLATILE (t)) | |
306 return false; | |
307 | |
308 /* Do not care about a local automatic that is not static. */ | |
309 if (!TREE_STATIC (t) && !DECL_EXTERNAL (t)) | |
310 return false; | |
311 | |
312 if (DECL_EXTERNAL (t) || TREE_PUBLIC (t)) | |
313 return false; | |
314 | |
315 /* We cannot touch decls where the type needs constructing. */ | |
316 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (t))) | |
317 return false; | |
318 | |
319 /* This is a variable we care about. Check if we have seen it | |
320 before, and if not add it the set of variables we care about. */ | |
321 if (!bitmap_bit_p (all_module_statics, DECL_UID (t))) | |
322 add_static_var (t); | |
323 | |
324 return true; | |
325 } | |
326 | |
327 /* Mark tree T as having address taken. */ | |
328 | |
329 static void | |
330 mark_address_taken (tree x) | |
331 { | |
332 if (TREE_CODE (x) == VAR_DECL | |
333 && module_statics_escape && has_proper_scope_for_analysis (x)) | |
334 bitmap_set_bit (module_statics_escape, DECL_UID (x)); | |
335 } | |
336 | |
337 /* Mark load of T. */ | |
338 | |
339 static void | |
340 mark_load (ipa_reference_local_vars_info_t local, | |
341 tree t) | |
342 { | |
343 if (TREE_CODE (t) == VAR_DECL | |
344 && has_proper_scope_for_analysis (t)) | |
345 bitmap_set_bit (local->statics_read, DECL_UID (t)); | |
346 } | |
347 | |
348 /* Mark store of T. */ | |
349 | |
350 static void | |
351 mark_store (ipa_reference_local_vars_info_t local, | |
352 tree t) | |
353 { | |
354 if (TREE_CODE (t) == VAR_DECL | |
355 && has_proper_scope_for_analysis (t)) | |
356 { | |
357 if (local) | |
358 bitmap_set_bit (local->statics_written, DECL_UID (t)); | |
359 /* Mark the write so we can tell which statics are | |
360 readonly. */ | |
361 if (module_statics_written) | |
362 bitmap_set_bit (module_statics_written, DECL_UID (t)); | |
363 } | |
364 } | |
365 | |
366 /* Look for memory clobber and set read_all/write_all if present. */ | |
367 | |
368 static void | |
369 check_asm_memory_clobber (ipa_reference_local_vars_info_t local, gimple stmt) | |
370 { | |
371 size_t i; | |
372 tree op; | |
373 | |
374 for (i = 0; i < gimple_asm_nclobbers (stmt); i++) | |
375 { | |
376 op = gimple_asm_clobber_op (stmt, i); | |
377 if (simple_cst_equal(TREE_VALUE (op), memory_identifier_string) == 1) | |
378 { | |
379 /* Abandon all hope, ye who enter here. */ | |
380 local->calls_read_all = true; | |
381 local->calls_write_all = true; | |
382 } | |
383 } | |
384 } | |
385 | |
386 /* Look for external calls and set read_all/write_all correspondingly. */ | |
387 | |
388 static void | |
389 check_call (ipa_reference_local_vars_info_t local, gimple stmt) | |
390 { | |
391 int flags = gimple_call_flags (stmt); | |
392 tree callee_t = gimple_call_fndecl (stmt); | |
393 enum availability avail = AVAIL_NOT_AVAILABLE; | |
394 | |
395 if (callee_t) | |
396 { | |
397 struct cgraph_node* callee = cgraph_node(callee_t); | |
398 avail = cgraph_function_body_availability (callee); | |
399 } | |
400 | |
401 if (avail <= AVAIL_OVERWRITABLE) | |
402 if (local) | |
403 { | |
404 if (flags & ECF_CONST) | |
405 ; | |
406 else if (flags & ECF_PURE) | |
407 local->calls_read_all = true; | |
408 else | |
409 { | |
410 local->calls_read_all = true; | |
411 local->calls_write_all = true; | |
412 } | |
413 } | |
414 /* TODO: To be able to produce sane results, we should also handle | |
415 common builtins, in particular throw. | |
416 Indirect calls hsould be only counted and as inliner is replacing them | |
417 by direct calls, we can conclude if any indirect calls are left in body */ | |
418 } | |
419 | |
420 /* TP is the part of the tree currently under the microscope. | |
421 WALK_SUBTREES is part of the walk_tree api but is unused here. | |
422 DATA is cgraph_node of the function being walked. */ | |
423 | |
424 static tree | |
425 scan_stmt_for_static_refs (gimple_stmt_iterator *gsip, | |
426 struct cgraph_node *fn) | |
427 { | |
428 gimple stmt = gsi_stmt (*gsip); | |
429 ipa_reference_local_vars_info_t local = NULL; | |
430 unsigned int i; | |
431 bitmap_iterator bi; | |
432 | |
433 if (fn) | |
434 local = get_reference_vars_info (fn)->local; | |
435 | |
436 if (gimple_loaded_syms (stmt)) | |
437 EXECUTE_IF_SET_IN_BITMAP (gimple_loaded_syms (stmt), 0, i, bi) | |
438 mark_load (local, referenced_var_lookup (i)); | |
439 if (gimple_stored_syms (stmt)) | |
440 EXECUTE_IF_SET_IN_BITMAP (gimple_stored_syms (stmt), 0, i, bi) | |
441 mark_store (local, referenced_var_lookup (i)); | |
442 if (gimple_addresses_taken (stmt)) | |
443 EXECUTE_IF_SET_IN_BITMAP (gimple_addresses_taken (stmt), 0, i, bi) | |
444 mark_address_taken (referenced_var_lookup (i)); | |
445 | |
446 switch (gimple_code (stmt)) | |
447 { | |
448 case GIMPLE_CALL: | |
449 check_call (local, stmt); | |
450 break; | |
451 | |
452 case GIMPLE_ASM: | |
453 check_asm_memory_clobber (local, stmt); | |
454 break; | |
455 | |
456 /* We used to check nonlocal labels here and set them as potentially modifying | |
457 everything. This is not needed, since we can get to nonlocal label only | |
458 from callee and thus we will get info propagated. */ | |
459 | |
460 default: | |
461 break; | |
462 } | |
463 | |
464 return NULL; | |
465 } | |
466 | |
467 /* Call-back to scan variable initializers for static references. | |
468 Called using walk_tree. */ | |
469 | |
470 static tree | |
471 scan_initializer_for_static_refs (tree *tp, int *walk_subtrees, | |
472 void *data ATTRIBUTE_UNUSED) | |
473 { | |
474 tree t = *tp; | |
475 | |
476 if (TREE_CODE (t) == ADDR_EXPR) | |
477 { | |
478 mark_address_taken (get_base_var (t)); | |
479 *walk_subtrees = 0; | |
480 } | |
481 /* Save some cycles by not walking types and declaration as we | |
482 won't find anything useful there anyway. */ | |
483 else if (IS_TYPE_OR_DECL_P (*tp)) | |
484 *walk_subtrees = 0; | |
485 | |
486 return NULL; | |
487 } | |
488 | |
489 /* Lookup the tree node for the static variable that has UID. */ | |
490 static tree | |
491 get_static_decl (int index) | |
492 { | |
493 splay_tree_node stn = | |
494 splay_tree_lookup (reference_vars_to_consider, index); | |
495 if (stn) | |
496 return (tree)stn->value; | |
497 return NULL; | |
498 } | |
499 | |
500 /* Lookup the tree node for the static variable that has UID and | |
501 convert the name to a string for debugging. */ | |
502 | |
503 static const char * | |
504 get_static_name (int index) | |
505 { | |
506 splay_tree_node stn = | |
507 splay_tree_lookup (reference_vars_to_consider, index); | |
508 if (stn) | |
509 return lang_hooks.decl_printable_name ((tree)(stn->value), 2); | |
510 return NULL; | |
511 } | |
512 | |
513 /* Or in all of the bits from every callee of X into X_GLOBAL, the caller's cycle, | |
514 bit vector. There are several cases to check to avoid the sparse | |
515 bitmap oring. */ | |
516 | |
517 static void | |
518 propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x) | |
519 { | |
520 struct cgraph_edge *e; | |
521 for (e = x->callees; e; e = e->next_callee) | |
522 { | |
523 struct cgraph_node *y = e->callee; | |
524 | |
525 /* Only look at the master nodes and skip external nodes. */ | |
526 if (cgraph_function_body_availability (e->callee) > AVAIL_OVERWRITABLE) | |
527 { | |
528 if (get_reference_vars_info (y)) | |
529 { | |
530 ipa_reference_vars_info_t y_info | |
531 = get_reference_vars_info (y); | |
532 ipa_reference_global_vars_info_t y_global = y_info->global; | |
533 | |
534 /* Calls in current cycle do not have global computed yet. */ | |
535 if (!y_info->global) | |
536 continue; | |
537 | |
538 if (x_global->statics_read | |
539 != all_module_statics) | |
540 { | |
541 if (y_global->statics_read | |
542 == all_module_statics) | |
543 { | |
544 BITMAP_FREE (x_global->statics_read); | |
545 x_global->statics_read | |
546 = all_module_statics; | |
547 } | |
548 /* Skip bitmaps that are pointer equal to node's bitmap | |
549 (no reason to spin within the cycle). */ | |
550 else if (x_global->statics_read | |
551 != y_global->statics_read) | |
552 bitmap_ior_into (x_global->statics_read, | |
553 y_global->statics_read); | |
554 } | |
555 | |
556 if (x_global->statics_written | |
557 != all_module_statics) | |
558 { | |
559 if (y_global->statics_written | |
560 == all_module_statics) | |
561 { | |
562 BITMAP_FREE (x_global->statics_written); | |
563 x_global->statics_written | |
564 = all_module_statics; | |
565 } | |
566 /* Skip bitmaps that are pointer equal to node's bitmap | |
567 (no reason to spin within the cycle). */ | |
568 else if (x_global->statics_written | |
569 != y_global->statics_written) | |
570 bitmap_ior_into (x_global->statics_written, | |
571 y_global->statics_written); | |
572 } | |
573 } | |
574 else | |
575 gcc_unreachable (); | |
576 } | |
577 } | |
578 } | |
579 | |
580 /* The init routine for analyzing global static variable usage. See | |
581 comments at top for description. */ | |
582 static void | |
583 ipa_init (void) | |
584 { | |
585 memory_identifier_string = build_string(7, "memory"); | |
586 | |
587 reference_vars_to_consider = | |
588 splay_tree_new_ggc (splay_tree_compare_ints); | |
589 | |
590 bitmap_obstack_initialize (&local_info_obstack); | |
591 bitmap_obstack_initialize (&global_info_obstack); | |
592 module_statics_escape = BITMAP_ALLOC (&local_info_obstack); | |
593 module_statics_written = BITMAP_ALLOC (&local_info_obstack); | |
594 all_module_statics = BITMAP_ALLOC (&global_info_obstack); | |
595 | |
596 /* There are some shared nodes, in particular the initializers on | |
597 static declarations. We do not need to scan them more than once | |
598 since all we would be interested in are the addressof | |
599 operations. */ | |
600 visited_nodes = pointer_set_create (); | |
601 } | |
602 | |
603 /* Check out the rhs of a static or global initialization VNODE to see | |
604 if any of them contain addressof operations. Note that some of | |
605 these variables may not even be referenced in the code in this | |
606 compilation unit but their right hand sides may contain references | |
607 to variables defined within this unit. */ | |
608 | |
609 static void | |
610 analyze_variable (struct varpool_node *vnode) | |
611 { | |
612 struct walk_stmt_info wi; | |
613 tree global = vnode->decl; | |
614 | |
615 memset (&wi, 0, sizeof (wi)); | |
616 wi.pset = visited_nodes; | |
617 walk_tree (&DECL_INITIAL (global), scan_initializer_for_static_refs, | |
618 &wi, wi.pset); | |
619 } | |
620 | |
621 /* Set up the persistent info for FN. */ | |
622 | |
623 static ipa_reference_local_vars_info_t | |
624 init_function_info (struct cgraph_node *fn) | |
625 { | |
626 ipa_reference_vars_info_t info | |
627 = XCNEW (struct ipa_reference_vars_info_d); | |
628 ipa_reference_local_vars_info_t l | |
629 = XCNEW (struct ipa_reference_local_vars_info_d); | |
630 | |
631 /* Add the info to the tree's annotation. */ | |
632 set_reference_vars_info (fn, info); | |
633 | |
634 info->local = l; | |
635 l->statics_read = BITMAP_ALLOC (&local_info_obstack); | |
636 l->statics_written = BITMAP_ALLOC (&local_info_obstack); | |
637 | |
638 return l; | |
639 } | |
640 | |
641 /* This is the main routine for finding the reference patterns for | |
642 global variables within a function FN. */ | |
643 | |
644 static void | |
645 analyze_function (struct cgraph_node *fn) | |
646 { | |
647 tree decl = fn->decl; | |
648 struct function *this_cfun = DECL_STRUCT_FUNCTION (decl); | |
649 basic_block this_block; | |
650 #ifdef ENABLE_CHECKING | |
651 tree step; | |
652 #endif | |
653 | |
654 if (dump_file) | |
655 fprintf (dump_file, "\n local analysis of %s\n", cgraph_node_name (fn)); | |
656 | |
657 push_cfun (DECL_STRUCT_FUNCTION (decl)); | |
658 current_function_decl = decl; | |
659 | |
660 init_function_info (fn); | |
661 FOR_EACH_BB_FN (this_block, this_cfun) | |
662 { | |
663 gimple_stmt_iterator gsi; | |
664 gimple phi; | |
665 tree op; | |
666 use_operand_p use; | |
667 ssa_op_iter iter; | |
668 | |
669 /* Find the addresses taken in phi node arguments. */ | |
670 for (gsi = gsi_start_phis (this_block); | |
671 !gsi_end_p (gsi); | |
672 gsi_next (&gsi)) | |
673 { | |
674 phi = gsi_stmt (gsi); | |
675 FOR_EACH_PHI_ARG (use, phi, iter, SSA_OP_USE) | |
676 { | |
677 op = USE_FROM_PTR (use); | |
678 if (TREE_CODE (op) == ADDR_EXPR) | |
679 mark_address_taken (get_base_var (op)); | |
680 } | |
681 } | |
682 | |
683 for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi)) | |
684 scan_stmt_for_static_refs (&gsi, fn); | |
685 } | |
686 | |
687 #ifdef ENABLE_CHECKING | |
688 /* Verify that all local initializers was expanded by gimplifier. */ | |
689 for (step = DECL_STRUCT_FUNCTION (decl)->local_decls; | |
690 step; | |
691 step = TREE_CHAIN (step)) | |
692 { | |
693 tree var = TREE_VALUE (step); | |
694 if (TREE_CODE (var) == VAR_DECL | |
695 && DECL_INITIAL (var) | |
696 && !TREE_STATIC (var)) | |
697 gcc_unreachable (); | |
698 } | |
699 #endif | |
700 pop_cfun (); | |
701 current_function_decl = NULL; | |
702 } | |
703 | |
704 /* Remove local data associated with function FN. */ | |
705 static void | |
706 clean_function_local_data (struct cgraph_node *fn) | |
707 { | |
708 ipa_reference_vars_info_t info = get_reference_vars_info (fn); | |
709 ipa_reference_local_vars_info_t l = info->local; | |
710 if (l) | |
711 { | |
712 if (l->statics_read | |
713 && l->statics_read != all_module_statics) | |
714 BITMAP_FREE (l->statics_read); | |
715 if (l->statics_written | |
716 &&l->statics_written != all_module_statics) | |
717 BITMAP_FREE (l->statics_written); | |
718 free (l); | |
719 info->local = NULL; | |
720 } | |
721 } | |
722 | |
723 /* Remove all data associated with function FN. */ | |
724 | |
725 static void | |
726 clean_function (struct cgraph_node *fn) | |
727 { | |
728 ipa_reference_vars_info_t info = get_reference_vars_info (fn); | |
729 ipa_reference_global_vars_info_t g = info->global; | |
730 | |
731 clean_function_local_data (fn); | |
732 if (g) | |
733 { | |
734 if (g->statics_read | |
735 && g->statics_read != all_module_statics) | |
736 BITMAP_FREE (g->statics_read); | |
737 | |
738 if (g->statics_written | |
739 && g->statics_written != all_module_statics) | |
740 BITMAP_FREE (g->statics_written); | |
741 | |
742 if (g->statics_not_read | |
743 && g->statics_not_read != all_module_statics) | |
744 BITMAP_FREE (g->statics_not_read); | |
745 | |
746 if (g->statics_not_written | |
747 && g->statics_not_written != all_module_statics) | |
748 BITMAP_FREE (g->statics_not_written); | |
749 free (g); | |
750 info->global = NULL; | |
751 } | |
752 | |
753 free (get_reference_vars_info (fn)); | |
754 set_reference_vars_info (fn, NULL); | |
755 } | |
756 | |
757 /* Called when new function is inserted to callgraph late. */ | |
758 static void | |
759 add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) | |
760 { | |
761 /* There are some shared nodes, in particular the initializers on | |
762 static declarations. We do not need to scan them more than once | |
763 since all we would be interested in are the addressof | |
764 operations. */ | |
765 analyze_function (node); | |
766 visited_nodes = NULL; | |
767 } | |
768 | |
769 static bitmap | |
770 copy_local_bitmap (bitmap src) | |
771 { | |
772 bitmap dst; | |
773 if (!src) | |
774 return NULL; | |
775 if (src == all_module_statics) | |
776 return all_module_statics; | |
777 dst = BITMAP_ALLOC (&local_info_obstack); | |
778 bitmap_copy (dst, src); | |
779 return dst; | |
780 } | |
781 | |
782 static bitmap | |
783 copy_global_bitmap (bitmap src) | |
784 { | |
785 bitmap dst; | |
786 if (!src) | |
787 return NULL; | |
788 if (src == all_module_statics) | |
789 return all_module_statics; | |
790 dst = BITMAP_ALLOC (&global_info_obstack); | |
791 bitmap_copy (dst, src); | |
792 return dst; | |
793 } | |
794 | |
795 /* Called when new clone is inserted to callgraph late. */ | |
796 | |
797 static void | |
798 duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst, | |
799 void *data ATTRIBUTE_UNUSED) | |
800 { | |
801 ipa_reference_global_vars_info_t ginfo; | |
802 ipa_reference_local_vars_info_t linfo; | |
803 ipa_reference_global_vars_info_t dst_ginfo; | |
804 ipa_reference_local_vars_info_t dst_linfo; | |
805 | |
806 ginfo = get_global_reference_vars_info (src); | |
807 linfo = get_local_reference_vars_info (src); | |
808 if (!linfo && !ginfo) | |
809 return; | |
810 init_function_info (dst); | |
811 if (linfo) | |
812 { | |
813 dst_linfo = get_local_reference_vars_info (dst); | |
814 dst_linfo->statics_read = copy_local_bitmap (linfo->statics_read); | |
815 dst_linfo->statics_written = copy_local_bitmap (linfo->statics_written); | |
816 dst_linfo->calls_read_all = linfo->calls_read_all; | |
817 dst_linfo->calls_write_all = linfo->calls_write_all; | |
818 } | |
819 if (ginfo) | |
820 { | |
821 get_reference_vars_info (dst)->global = XCNEW (struct ipa_reference_global_vars_info_d); | |
822 dst_ginfo = get_global_reference_vars_info (dst); | |
823 dst_ginfo->statics_read = copy_global_bitmap (ginfo->statics_read); | |
824 dst_ginfo->statics_written = copy_global_bitmap (ginfo->statics_written); | |
825 dst_ginfo->statics_not_read = copy_global_bitmap (ginfo->statics_not_read); | |
826 dst_ginfo->statics_not_written = copy_global_bitmap (ginfo->statics_not_written); | |
827 } | |
828 } | |
829 | |
830 /* Called when node is removed. */ | |
831 | |
832 static void | |
833 remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) | |
834 { | |
835 if (get_reference_vars_info (node)) | |
836 clean_function (node); | |
837 } | |
838 | |
839 /* Analyze each function in the cgraph to see which global or statics | |
840 are read or written. */ | |
841 | |
842 static void | |
843 generate_summary (void) | |
844 { | |
845 struct cgraph_node *node; | |
846 struct varpool_node *vnode; | |
847 unsigned int index; | |
848 bitmap_iterator bi; | |
849 bitmap module_statics_readonly; | |
850 bitmap bm_temp; | |
851 | |
852 function_insertion_hook_holder = | |
853 cgraph_add_function_insertion_hook (&add_new_function, NULL); | |
854 node_removal_hook_holder = | |
855 cgraph_add_node_removal_hook (&remove_node_data, NULL); | |
856 node_duplication_hook_holder = | |
857 cgraph_add_node_duplication_hook (&duplicate_node_data, NULL); | |
858 ipa_init (); | |
859 module_statics_readonly = BITMAP_ALLOC (&local_info_obstack); | |
860 bm_temp = BITMAP_ALLOC (&local_info_obstack); | |
861 | |
862 /* Process all of the variables first. */ | |
863 FOR_EACH_STATIC_INITIALIZER (vnode) | |
864 analyze_variable (vnode); | |
865 | |
866 /* Process all of the functions next. | |
867 | |
868 We do not want to process any of the clones so we check that this | |
869 is a master clone. However, we do need to process any | |
870 AVAIL_OVERWRITABLE functions (these are never clones) because | |
871 they may cause a static variable to escape. The code that can | |
872 overwrite such a function cannot access the statics because it | |
873 would not be in the same compilation unit. When the analysis is | |
874 finished, the computed information of these AVAIL_OVERWRITABLE is | |
875 replaced with worst case info. | |
876 */ | |
877 for (node = cgraph_nodes; node; node = node->next) | |
878 if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) | |
879 analyze_function (node); | |
880 | |
881 pointer_set_destroy (visited_nodes); | |
882 visited_nodes = NULL; | |
883 | |
884 /* Prune out the variables that were found to behave badly | |
885 (i.e. have their address taken). */ | |
886 EXECUTE_IF_SET_IN_BITMAP (module_statics_escape, 0, index, bi) | |
887 { | |
888 splay_tree_remove (reference_vars_to_consider, index); | |
889 } | |
890 | |
891 bitmap_and_compl_into (all_module_statics, | |
892 module_statics_escape); | |
893 | |
894 bitmap_and_compl (module_statics_readonly, all_module_statics, | |
895 module_statics_written); | |
896 | |
897 /* If the address is not taken, we can unset the addressable bit | |
898 on this variable. */ | |
899 EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi) | |
900 { | |
901 tree var = get_static_decl (index); | |
902 TREE_ADDRESSABLE (var) = 0; | |
903 if (dump_file) | |
904 fprintf (dump_file, "Not TREE_ADDRESSABLE var %s\n", | |
905 get_static_name (index)); | |
906 } | |
907 | |
908 /* If the variable is never written, we can set the TREE_READONLY | |
909 flag. Additionally if it has a DECL_INITIAL that is made up of | |
910 constants we can treat the entire global as a constant. */ | |
911 | |
912 bitmap_and_compl (module_statics_readonly, all_module_statics, | |
913 module_statics_written); | |
914 EXECUTE_IF_SET_IN_BITMAP (module_statics_readonly, 0, index, bi) | |
915 { | |
916 tree var = get_static_decl (index); | |
917 | |
918 /* Ignore variables in named sections - changing TREE_READONLY | |
919 changes the section flags, potentially causing conflicts with | |
920 other variables in the same named section. */ | |
921 if (DECL_SECTION_NAME (var) == NULL_TREE) | |
922 { | |
923 TREE_READONLY (var) = 1; | |
924 if (dump_file) | |
925 fprintf (dump_file, "read-only var %s\n", | |
926 get_static_name (index)); | |
927 } | |
928 } | |
929 | |
930 BITMAP_FREE(module_statics_escape); | |
931 BITMAP_FREE(module_statics_written); | |
932 module_statics_escape = NULL; | |
933 module_statics_written = NULL; | |
934 | |
935 if (dump_file) | |
936 EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi) | |
937 { | |
938 fprintf (dump_file, "\nPromotable global:%s", | |
939 get_static_name (index)); | |
940 } | |
941 | |
942 for (node = cgraph_nodes; node; node = node->next) | |
943 if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) | |
944 { | |
945 ipa_reference_local_vars_info_t l; | |
946 l = get_reference_vars_info (node)->local; | |
947 | |
948 /* Any variables that are not in all_module_statics are | |
949 removed from the local maps. This will include all of the | |
950 variables that were found to escape in the function | |
951 scanning. */ | |
952 bitmap_and_into (l->statics_read, | |
953 all_module_statics); | |
954 bitmap_and_into (l->statics_written, | |
955 all_module_statics); | |
956 } | |
957 | |
958 BITMAP_FREE(module_statics_readonly); | |
959 BITMAP_FREE(bm_temp); | |
960 | |
961 if (dump_file) | |
962 for (node = cgraph_nodes; node; node = node->next) | |
963 if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) | |
964 { | |
965 ipa_reference_local_vars_info_t l; | |
966 unsigned int index; | |
967 bitmap_iterator bi; | |
968 | |
969 l = get_reference_vars_info (node)->local; | |
970 fprintf (dump_file, | |
971 "\nFunction name:%s/%i:", | |
972 cgraph_node_name (node), node->uid); | |
973 fprintf (dump_file, "\n locals read: "); | |
974 EXECUTE_IF_SET_IN_BITMAP (l->statics_read, | |
975 0, index, bi) | |
976 { | |
977 fprintf (dump_file, "%s ", | |
978 get_static_name (index)); | |
979 } | |
980 fprintf (dump_file, "\n locals written: "); | |
981 EXECUTE_IF_SET_IN_BITMAP (l->statics_written, | |
982 0, index, bi) | |
983 { | |
984 fprintf(dump_file, "%s ", | |
985 get_static_name (index)); | |
986 } | |
987 if (l->calls_read_all) | |
988 fprintf (dump_file, "\n calls read all: "); | |
989 if (l->calls_write_all) | |
990 fprintf (dump_file, "\n calls read all: "); | |
991 } | |
992 } | |
993 | |
994 /* Produce the global information by preforming a transitive closure | |
995 on the local information that was produced by ipa_analyze_function | |
996 and ipa_analyze_variable. */ | |
997 | |
998 static unsigned int | |
999 propagate (void) | |
1000 { | |
1001 struct cgraph_node *node; | |
1002 struct cgraph_node *w; | |
1003 struct cgraph_node **order = | |
1004 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); | |
1005 int order_pos = ipa_utils_reduced_inorder (order, false, true); | |
1006 int i; | |
1007 | |
1008 cgraph_remove_function_insertion_hook (function_insertion_hook_holder); | |
1009 if (dump_file) | |
1010 dump_cgraph (dump_file); | |
1011 | |
1012 /* Propagate the local information thru the call graph to produce | |
1013 the global information. All the nodes within a cycle will have | |
1014 the same info so we collapse cycles first. Then we can do the | |
1015 propagation in one pass from the leaves to the roots. */ | |
1016 order_pos = ipa_utils_reduced_inorder (order, true, true); | |
1017 if (dump_file) | |
1018 ipa_utils_print_order(dump_file, "reduced", order, order_pos); | |
1019 | |
1020 for (i = 0; i < order_pos; i++ ) | |
1021 { | |
1022 ipa_reference_vars_info_t node_info; | |
1023 ipa_reference_global_vars_info_t node_g = | |
1024 XCNEW (struct ipa_reference_global_vars_info_d); | |
1025 ipa_reference_local_vars_info_t node_l; | |
1026 | |
1027 bool read_all; | |
1028 bool write_all; | |
1029 struct ipa_dfs_info * w_info; | |
1030 | |
1031 node = order[i]; | |
1032 node_info = get_reference_vars_info (node); | |
1033 if (!node_info) | |
1034 { | |
1035 dump_cgraph_node (stderr, node); | |
1036 dump_cgraph (stderr); | |
1037 gcc_unreachable (); | |
1038 } | |
1039 | |
1040 gcc_assert (!node_info->global); | |
1041 node_l = node_info->local; | |
1042 | |
1043 read_all = node_l->calls_read_all; | |
1044 write_all = node_l->calls_write_all; | |
1045 | |
1046 /* If any node in a cycle is calls_read_all or calls_write_all | |
1047 they all are. */ | |
1048 w_info = (struct ipa_dfs_info *) node->aux; | |
1049 w = w_info->next_cycle; | |
1050 while (w) | |
1051 { | |
1052 ipa_reference_local_vars_info_t w_l = | |
1053 get_reference_vars_info (w)->local; | |
1054 read_all |= w_l->calls_read_all; | |
1055 write_all |= w_l->calls_write_all; | |
1056 | |
1057 w_info = (struct ipa_dfs_info *) w->aux; | |
1058 w = w_info->next_cycle; | |
1059 } | |
1060 | |
1061 /* Initialized the bitmaps for the reduced nodes */ | |
1062 if (read_all) | |
1063 node_g->statics_read = all_module_statics; | |
1064 else | |
1065 { | |
1066 node_g->statics_read = BITMAP_ALLOC (&global_info_obstack); | |
1067 bitmap_copy (node_g->statics_read, | |
1068 node_l->statics_read); | |
1069 } | |
1070 | |
1071 if (write_all) | |
1072 node_g->statics_written = all_module_statics; | |
1073 else | |
1074 { | |
1075 node_g->statics_written = BITMAP_ALLOC (&global_info_obstack); | |
1076 bitmap_copy (node_g->statics_written, | |
1077 node_l->statics_written); | |
1078 } | |
1079 | |
1080 propagate_bits (node_g, node); | |
1081 w_info = (struct ipa_dfs_info *) node->aux; | |
1082 w = w_info->next_cycle; | |
1083 while (w) | |
1084 { | |
1085 ipa_reference_vars_info_t w_ri = | |
1086 get_reference_vars_info (w); | |
1087 ipa_reference_local_vars_info_t w_l = w_ri->local; | |
1088 | |
1089 /* These global bitmaps are initialized from the local info | |
1090 of all of the nodes in the region. However there is no | |
1091 need to do any work if the bitmaps were set to | |
1092 all_module_statics. */ | |
1093 if (!read_all) | |
1094 bitmap_ior_into (node_g->statics_read, | |
1095 w_l->statics_read); | |
1096 if (!write_all) | |
1097 bitmap_ior_into (node_g->statics_written, | |
1098 w_l->statics_written); | |
1099 propagate_bits (node_g, w); | |
1100 w_info = (struct ipa_dfs_info *) w->aux; | |
1101 w = w_info->next_cycle; | |
1102 } | |
1103 | |
1104 /* All nodes within a cycle have the same global info bitmaps. */ | |
1105 node_info->global = node_g; | |
1106 w_info = (struct ipa_dfs_info *) node->aux; | |
1107 w = w_info->next_cycle; | |
1108 while (w) | |
1109 { | |
1110 ipa_reference_vars_info_t w_ri = | |
1111 get_reference_vars_info (w); | |
1112 | |
1113 gcc_assert (!w_ri->global); | |
1114 w_ri->global = XCNEW (struct ipa_reference_global_vars_info_d); | |
1115 w_ri->global->statics_read = copy_global_bitmap (node_g->statics_read); | |
1116 w_ri->global->statics_written = copy_global_bitmap (node_g->statics_written); | |
1117 | |
1118 w_info = (struct ipa_dfs_info *) w->aux; | |
1119 w = w_info->next_cycle; | |
1120 } | |
1121 } | |
1122 | |
1123 if (dump_file) | |
1124 { | |
1125 for (i = 0; i < order_pos; i++ ) | |
1126 { | |
1127 ipa_reference_vars_info_t node_info; | |
1128 ipa_reference_global_vars_info_t node_g; | |
1129 ipa_reference_local_vars_info_t node_l; | |
1130 unsigned int index; | |
1131 bitmap_iterator bi; | |
1132 struct ipa_dfs_info * w_info; | |
1133 | |
1134 node = order[i]; | |
1135 node_info = get_reference_vars_info (node); | |
1136 node_g = node_info->global; | |
1137 node_l = node_info->local; | |
1138 fprintf (dump_file, | |
1139 "\nFunction name:%s/%i:", | |
1140 cgraph_node_name (node), node->uid); | |
1141 fprintf (dump_file, "\n locals read: "); | |
1142 EXECUTE_IF_SET_IN_BITMAP (node_l->statics_read, | |
1143 0, index, bi) | |
1144 { | |
1145 fprintf (dump_file, "%s ", | |
1146 get_static_name (index)); | |
1147 } | |
1148 fprintf (dump_file, "\n locals written: "); | |
1149 EXECUTE_IF_SET_IN_BITMAP (node_l->statics_written, | |
1150 0, index, bi) | |
1151 { | |
1152 fprintf(dump_file, "%s ", | |
1153 get_static_name (index)); | |
1154 } | |
1155 | |
1156 w_info = (struct ipa_dfs_info *) node->aux; | |
1157 w = w_info->next_cycle; | |
1158 while (w) | |
1159 { | |
1160 ipa_reference_vars_info_t w_ri = | |
1161 get_reference_vars_info (w); | |
1162 ipa_reference_local_vars_info_t w_l = w_ri->local; | |
1163 fprintf (dump_file, "\n next cycle: %s/%i ", | |
1164 cgraph_node_name (w), w->uid); | |
1165 fprintf (dump_file, "\n locals read: "); | |
1166 EXECUTE_IF_SET_IN_BITMAP (w_l->statics_read, | |
1167 0, index, bi) | |
1168 { | |
1169 fprintf (dump_file, "%s ", | |
1170 get_static_name (index)); | |
1171 } | |
1172 | |
1173 fprintf (dump_file, "\n locals written: "); | |
1174 EXECUTE_IF_SET_IN_BITMAP (w_l->statics_written, | |
1175 0, index, bi) | |
1176 { | |
1177 fprintf(dump_file, "%s ", | |
1178 get_static_name (index)); | |
1179 } | |
1180 | |
1181 | |
1182 w_info = (struct ipa_dfs_info *) w->aux; | |
1183 w = w_info->next_cycle; | |
1184 } | |
1185 fprintf (dump_file, "\n globals read: "); | |
1186 EXECUTE_IF_SET_IN_BITMAP (node_g->statics_read, | |
1187 0, index, bi) | |
1188 { | |
1189 fprintf (dump_file, "%s ", | |
1190 get_static_name (index)); | |
1191 } | |
1192 fprintf (dump_file, "\n globals written: "); | |
1193 EXECUTE_IF_SET_IN_BITMAP (node_g->statics_written, | |
1194 0, index, bi) | |
1195 { | |
1196 fprintf (dump_file, "%s ", | |
1197 get_static_name (index)); | |
1198 } | |
1199 } | |
1200 } | |
1201 | |
1202 /* Cleanup. */ | |
1203 for (i = 0; i < order_pos; i++ ) | |
1204 { | |
1205 ipa_reference_vars_info_t node_info; | |
1206 ipa_reference_global_vars_info_t node_g; | |
1207 node = order[i]; | |
1208 node_info = get_reference_vars_info (node); | |
1209 node_g = node_info->global; | |
1210 | |
1211 /* Create the complimentary sets. These are more useful for | |
1212 certain apis. */ | |
1213 node_g->statics_not_read = BITMAP_ALLOC (&global_info_obstack); | |
1214 node_g->statics_not_written = BITMAP_ALLOC (&global_info_obstack); | |
1215 | |
1216 if (node_g->statics_read != all_module_statics) | |
1217 bitmap_and_compl (node_g->statics_not_read, | |
1218 all_module_statics, | |
1219 node_g->statics_read); | |
1220 | |
1221 if (node_g->statics_written | |
1222 != all_module_statics) | |
1223 bitmap_and_compl (node_g->statics_not_written, | |
1224 all_module_statics, | |
1225 node_g->statics_written); | |
1226 } | |
1227 | |
1228 free (order); | |
1229 | |
1230 for (node = cgraph_nodes; node; node = node->next) | |
1231 { | |
1232 ipa_reference_vars_info_t node_info; | |
1233 node_info = get_reference_vars_info (node); | |
1234 /* Get rid of the aux information. */ | |
1235 | |
1236 if (node->aux) | |
1237 { | |
1238 free (node->aux); | |
1239 node->aux = NULL; | |
1240 } | |
1241 | |
1242 if (cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE) | |
1243 clean_function (node); | |
1244 else if (node_info) | |
1245 clean_function_local_data (node); | |
1246 } | |
1247 bitmap_obstack_release (&local_info_obstack); | |
1248 return 0; | |
1249 } | |
1250 | |
1251 | |
1252 static bool | |
1253 gate_reference (void) | |
1254 { | |
1255 return (flag_ipa_reference | |
1256 /* Don't bother doing anything if the program has errors. */ | |
1257 && !(errorcount || sorrycount)); | |
1258 } | |
1259 | |
1260 struct ipa_opt_pass pass_ipa_reference = | |
1261 { | |
1262 { | |
1263 IPA_PASS, | |
1264 "static-var", /* name */ | |
1265 gate_reference, /* gate */ | |
1266 propagate, /* execute */ | |
1267 NULL, /* sub */ | |
1268 NULL, /* next */ | |
1269 0, /* static_pass_number */ | |
1270 TV_IPA_REFERENCE, /* tv_id */ | |
1271 0, /* properties_required */ | |
1272 0, /* properties_provided */ | |
1273 0, /* properties_destroyed */ | |
1274 0, /* todo_flags_start */ | |
1275 0 /* todo_flags_finish */ | |
1276 }, | |
1277 generate_summary, /* generate_summary */ | |
1278 NULL, /* write_summary */ | |
1279 NULL, /* read_summary */ | |
1280 NULL, /* function_read_summary */ | |
1281 0, /* TODOs */ | |
1282 NULL, /* function_transform */ | |
1283 NULL /* variable_transform */ | |
1284 }; | |
1285 | |
1286 #include "gt-ipa-reference.h" |