PR rtl-optimization/49095
[official-gcc.git] / gcc / ipa-utils.c
blobde4f4b6e107b033d14a18dfe10123d23fd5fa9ea
1 /* Utilities for ipa analysis.
2 Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
3 Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "tree.h"
26 #include "tree-flow.h"
27 #include "tree-inline.h"
28 #include "tree-pass.h"
29 #include "langhooks.h"
30 #include "pointer-set.h"
31 #include "splay-tree.h"
32 #include "ggc.h"
33 #include "ipa-utils.h"
34 #include "ipa-reference.h"
35 #include "gimple.h"
36 #include "cgraph.h"
37 #include "output.h"
38 #include "flags.h"
39 #include "timevar.h"
40 #include "diagnostic.h"
41 #include "langhooks.h"
43 /* Debugging function for postorder and inorder code. NOTE is a string
44 that is printed before the nodes are printed. ORDER is an array of
45 cgraph_nodes that has COUNT useful nodes in it. */
47 void
48 ipa_print_order (FILE* out,
49 const char * note,
50 struct cgraph_node** order,
51 int count)
53 int i;
54 fprintf (out, "\n\n ordered call graph: %s\n", note);
56 for (i = count - 1; i >= 0; i--)
57 dump_cgraph_node(dump_file, order[i]);
58 fprintf (out, "\n");
59 fflush(out);
63 struct searchc_env {
64 struct cgraph_node **stack;
65 int stack_size;
66 struct cgraph_node **result;
67 int order_pos;
68 splay_tree nodes_marked_new;
69 bool reduce;
70 int count;
73 /* This is an implementation of Tarjan's strongly connected region
74 finder as reprinted in Aho Hopcraft and Ullman's The Design and
75 Analysis of Computer Programs (1975) pages 192-193. This version
76 has been customized for cgraph_nodes. The env parameter is because
77 it is recursive and there are no nested functions here. This
78 function should only be called from itself or
79 ipa_reduced_postorder. ENV is a stack env and would be
80 unnecessary if C had nested functions. V is the node to start
81 searching from. */
83 static void
84 searchc (struct searchc_env* env, struct cgraph_node *v,
85 bool (*ignore_edge) (struct cgraph_edge *))
87 struct cgraph_edge *edge;
88 struct ipa_dfs_info *v_info = (struct ipa_dfs_info *) v->aux;
90 /* mark node as old */
91 v_info->new_node = false;
92 splay_tree_remove (env->nodes_marked_new, v->uid);
94 v_info->dfn_number = env->count;
95 v_info->low_link = env->count;
96 env->count++;
97 env->stack[(env->stack_size)++] = v;
98 v_info->on_stack = true;
100 for (edge = v->callees; edge; edge = edge->next_callee)
102 struct ipa_dfs_info * w_info;
103 struct cgraph_node *w = edge->callee;
105 if (ignore_edge && ignore_edge (edge))
106 continue;
108 if (w->aux && cgraph_function_body_availability (edge->callee) > AVAIL_OVERWRITABLE)
110 w_info = (struct ipa_dfs_info *) w->aux;
111 if (w_info->new_node)
113 searchc (env, w, ignore_edge);
114 v_info->low_link =
115 (v_info->low_link < w_info->low_link) ?
116 v_info->low_link : w_info->low_link;
118 else
119 if ((w_info->dfn_number < v_info->dfn_number)
120 && (w_info->on_stack))
121 v_info->low_link =
122 (w_info->dfn_number < v_info->low_link) ?
123 w_info->dfn_number : v_info->low_link;
128 if (v_info->low_link == v_info->dfn_number)
130 struct cgraph_node *last = NULL;
131 struct cgraph_node *x;
132 struct ipa_dfs_info *x_info;
133 do {
134 x = env->stack[--(env->stack_size)];
135 x_info = (struct ipa_dfs_info *) x->aux;
136 x_info->on_stack = false;
138 if (env->reduce)
140 x_info->next_cycle = last;
141 last = x;
143 else
144 env->result[env->order_pos++] = x;
146 while (v != x);
147 if (env->reduce)
148 env->result[env->order_pos++] = v;
152 /* Topsort the call graph by caller relation. Put the result in ORDER.
154 The REDUCE flag is true if you want the cycles reduced to single nodes. Set
155 ALLOW_OVERWRITABLE if nodes with such availability should be included.
156 IGNORE_EDGE, if non-NULL is a hook that may make some edges insignificant
157 for the topological sort. */
160 ipa_reduced_postorder (struct cgraph_node **order,
161 bool reduce, bool allow_overwritable,
162 bool (*ignore_edge) (struct cgraph_edge *))
164 struct cgraph_node *node;
165 struct searchc_env env;
166 splay_tree_node result;
167 env.stack = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
168 env.stack_size = 0;
169 env.result = order;
170 env.order_pos = 0;
171 env.nodes_marked_new = splay_tree_new (splay_tree_compare_ints, 0, 0);
172 env.count = 1;
173 env.reduce = reduce;
175 for (node = cgraph_nodes; node; node = node->next)
177 enum availability avail = cgraph_function_body_availability (node);
179 if (avail > AVAIL_OVERWRITABLE
180 || (allow_overwritable
181 && (avail == AVAIL_OVERWRITABLE)))
183 /* Reuse the info if it is already there. */
184 struct ipa_dfs_info *info = (struct ipa_dfs_info *) node->aux;
185 if (!info)
186 info = XCNEW (struct ipa_dfs_info);
187 info->new_node = true;
188 info->on_stack = false;
189 info->next_cycle = NULL;
190 node->aux = info;
192 splay_tree_insert (env.nodes_marked_new,
193 (splay_tree_key)node->uid,
194 (splay_tree_value)node);
196 else
197 node->aux = NULL;
199 result = splay_tree_min (env.nodes_marked_new);
200 while (result)
202 node = (struct cgraph_node *)result->value;
203 searchc (&env, node, ignore_edge);
204 result = splay_tree_min (env.nodes_marked_new);
206 splay_tree_delete (env.nodes_marked_new);
207 free (env.stack);
209 return env.order_pos;
212 /* Deallocate all ipa_dfs_info structures pointed to by the aux pointer of call
213 graph nodes. */
215 void
216 ipa_free_postorder_info (void)
218 struct cgraph_node *node;
219 for (node = cgraph_nodes; node; node = node->next)
221 /* Get rid of the aux information. */
222 if (node->aux)
224 free (node->aux);
225 node->aux = NULL;
230 /* Fill array order with all nodes with output flag set in the reverse
231 topological order. Return the number of elements in the array. */
234 ipa_reverse_postorder (struct cgraph_node **order)
236 struct cgraph_node *node, *node2;
237 int stack_size = 0;
238 int order_pos = 0;
239 struct cgraph_edge *edge, last;
240 int pass;
242 struct cgraph_node **stack =
243 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
245 /* We have to deal with cycles nicely, so use a depth first traversal
246 output algorithm. Ignore the fact that some functions won't need
247 to be output and put them into order as well, so we get dependencies
248 right through inline functions. */
249 for (node = cgraph_nodes; node; node = node->next)
250 node->aux = NULL;
251 for (pass = 0; pass < 2; pass++)
252 for (node = cgraph_nodes; node; node = node->next)
253 if (!node->aux
254 && (pass
255 || (!node->address_taken
256 && !node->global.inlined_to
257 && !cgraph_only_called_directly_p (node))))
259 node2 = node;
260 if (!node->callers)
261 node->aux = &last;
262 else
263 node->aux = node->callers;
264 while (node2)
266 while (node2->aux != &last)
268 edge = (struct cgraph_edge *) node2->aux;
269 if (edge->next_caller)
270 node2->aux = edge->next_caller;
271 else
272 node2->aux = &last;
273 /* Break possible cycles involving always-inline
274 functions by ignoring edges from always-inline
275 functions to non-always-inline functions. */
276 if (DECL_DISREGARD_INLINE_LIMITS (edge->caller->decl)
277 && !DECL_DISREGARD_INLINE_LIMITS (edge->callee->decl))
278 continue;
279 if (!edge->caller->aux)
281 if (!edge->caller->callers)
282 edge->caller->aux = &last;
283 else
284 edge->caller->aux = edge->caller->callers;
285 stack[stack_size++] = node2;
286 node2 = edge->caller;
287 break;
290 if (node2->aux == &last)
292 order[order_pos++] = node2;
293 if (stack_size)
294 node2 = stack[--stack_size];
295 else
296 node2 = NULL;
300 free (stack);
301 for (node = cgraph_nodes; node; node = node->next)
302 node->aux = NULL;
303 return order_pos;
308 /* Given a memory reference T, will return the variable at the bottom
309 of the access. Unlike get_base_address, this will recurse thru
310 INDIRECT_REFS. */
312 tree
313 get_base_var (tree t)
315 while (!SSA_VAR_P (t)
316 && (!CONSTANT_CLASS_P (t))
317 && TREE_CODE (t) != LABEL_DECL
318 && TREE_CODE (t) != FUNCTION_DECL
319 && TREE_CODE (t) != CONST_DECL
320 && TREE_CODE (t) != CONSTRUCTOR)
322 t = TREE_OPERAND (t, 0);
324 return t;
328 /* Create a new cgraph node set. */
330 cgraph_node_set
331 cgraph_node_set_new (void)
333 cgraph_node_set new_node_set;
335 new_node_set = XCNEW (struct cgraph_node_set_def);
336 new_node_set->map = pointer_map_create ();
337 new_node_set->nodes = NULL;
338 return new_node_set;
342 /* Add cgraph_node NODE to cgraph_node_set SET. */
344 void
345 cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
347 void **slot;
349 slot = pointer_map_insert (set->map, node);
351 if (*slot)
353 int index = (size_t) *slot - 1;
354 gcc_checking_assert ((VEC_index (cgraph_node_ptr, set->nodes, index)
355 == node));
356 return;
359 *slot = (void *)(size_t) (VEC_length (cgraph_node_ptr, set->nodes) + 1);
361 /* Insert into node vector. */
362 VEC_safe_push (cgraph_node_ptr, heap, set->nodes, node);
366 /* Remove cgraph_node NODE from cgraph_node_set SET. */
368 void
369 cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
371 void **slot, **last_slot;
372 int index;
373 struct cgraph_node *last_node;
375 slot = pointer_map_contains (set->map, node);
376 if (slot == NULL || !*slot)
377 return;
379 index = (size_t) *slot - 1;
380 gcc_checking_assert (VEC_index (cgraph_node_ptr, set->nodes, index)
381 == node);
383 /* Remove from vector. We do this by swapping node with the last element
384 of the vector. */
385 last_node = VEC_pop (cgraph_node_ptr, set->nodes);
386 if (last_node != node)
388 last_slot = pointer_map_contains (set->map, last_node);
389 gcc_checking_assert (last_slot && *last_slot);
390 *last_slot = (void *)(size_t) (index + 1);
392 /* Move the last element to the original spot of NODE. */
393 VEC_replace (cgraph_node_ptr, set->nodes, index, last_node);
396 /* Remove element from hash table. */
397 *slot = NULL;
401 /* Find NODE in SET and return an iterator to it if found. A null iterator
402 is returned if NODE is not in SET. */
404 cgraph_node_set_iterator
405 cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
407 void **slot;
408 cgraph_node_set_iterator csi;
410 slot = pointer_map_contains (set->map, node);
411 if (slot == NULL || !*slot)
412 csi.index = (unsigned) ~0;
413 else
414 csi.index = (size_t)*slot - 1;
415 csi.set = set;
417 return csi;
421 /* Dump content of SET to file F. */
423 void
424 dump_cgraph_node_set (FILE *f, cgraph_node_set set)
426 cgraph_node_set_iterator iter;
428 for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
430 struct cgraph_node *node = csi_node (iter);
431 fprintf (f, " %s/%i", cgraph_node_name (node), node->uid);
433 fprintf (f, "\n");
437 /* Dump content of SET to stderr. */
439 DEBUG_FUNCTION void
440 debug_cgraph_node_set (cgraph_node_set set)
442 dump_cgraph_node_set (stderr, set);
446 /* Free varpool node set. */
448 void
449 free_cgraph_node_set (cgraph_node_set set)
451 VEC_free (cgraph_node_ptr, heap, set->nodes);
452 pointer_map_destroy (set->map);
453 free (set);
457 /* Create a new varpool node set. */
459 varpool_node_set
460 varpool_node_set_new (void)
462 varpool_node_set new_node_set;
464 new_node_set = XCNEW (struct varpool_node_set_def);
465 new_node_set->map = pointer_map_create ();
466 new_node_set->nodes = NULL;
467 return new_node_set;
471 /* Add varpool_node NODE to varpool_node_set SET. */
473 void
474 varpool_node_set_add (varpool_node_set set, struct varpool_node *node)
476 void **slot;
478 slot = pointer_map_insert (set->map, node);
480 if (*slot)
482 int index = (size_t) *slot - 1;
483 gcc_checking_assert ((VEC_index (varpool_node_ptr, set->nodes, index)
484 == node));
485 return;
488 *slot = (void *)(size_t) (VEC_length (varpool_node_ptr, set->nodes) + 1);
490 /* Insert into node vector. */
491 VEC_safe_push (varpool_node_ptr, heap, set->nodes, node);
495 /* Remove varpool_node NODE from varpool_node_set SET. */
497 void
498 varpool_node_set_remove (varpool_node_set set, struct varpool_node *node)
500 void **slot, **last_slot;
501 int index;
502 struct varpool_node *last_node;
504 slot = pointer_map_contains (set->map, node);
505 if (slot == NULL || !*slot)
506 return;
508 index = (size_t) *slot - 1;
509 gcc_checking_assert (VEC_index (varpool_node_ptr, set->nodes, index)
510 == node);
512 /* Remove from vector. We do this by swapping node with the last element
513 of the vector. */
514 last_node = VEC_pop (varpool_node_ptr, set->nodes);
515 if (last_node != node)
517 last_slot = pointer_map_contains (set->map, last_node);
518 gcc_checking_assert (last_slot && *last_slot);
519 *last_slot = (void *)(size_t) (index + 1);
521 /* Move the last element to the original spot of NODE. */
522 VEC_replace (varpool_node_ptr, set->nodes, index, last_node);
525 /* Remove element from hash table. */
526 *slot = NULL;
530 /* Find NODE in SET and return an iterator to it if found. A null iterator
531 is returned if NODE is not in SET. */
533 varpool_node_set_iterator
534 varpool_node_set_find (varpool_node_set set, struct varpool_node *node)
536 void **slot;
537 varpool_node_set_iterator vsi;
539 slot = pointer_map_contains (set->map, node);
540 if (slot == NULL || !*slot)
541 vsi.index = (unsigned) ~0;
542 else
543 vsi.index = (size_t)*slot - 1;
544 vsi.set = set;
546 return vsi;
550 /* Dump content of SET to file F. */
552 void
553 dump_varpool_node_set (FILE *f, varpool_node_set set)
555 varpool_node_set_iterator iter;
557 for (iter = vsi_start (set); !vsi_end_p (iter); vsi_next (&iter))
559 struct varpool_node *node = vsi_node (iter);
560 fprintf (f, " %s", varpool_node_name (node));
562 fprintf (f, "\n");
566 /* Free varpool node set. */
568 void
569 free_varpool_node_set (varpool_node_set set)
571 VEC_free (varpool_node_ptr, heap, set->nodes);
572 pointer_map_destroy (set->map);
573 free (set);
577 /* Dump content of SET to stderr. */
579 DEBUG_FUNCTION void
580 debug_varpool_node_set (varpool_node_set set)
582 dump_varpool_node_set (stderr, set);