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
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
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/>. */
23 #include "coretypes.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"
33 #include "ipa-utils.h"
34 #include "ipa-reference.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. */
48 ipa_print_order (FILE* out,
50 struct cgraph_node** order,
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]);
64 struct cgraph_node **stack;
66 struct cgraph_node **result;
68 splay_tree nodes_marked_new;
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
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;
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))
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);
115 (v_info->low_link < w_info->low_link) ?
116 v_info->low_link : w_info->low_link;
119 if ((w_info->dfn_number < v_info->dfn_number)
120 && (w_info->on_stack))
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;
134 x = env->stack[--(env->stack_size)];
135 x_info = (struct ipa_dfs_info *) x->aux;
136 x_info->on_stack = false;
140 x_info->next_cycle = last;
144 env->result[env->order_pos++] = x;
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);
171 env.nodes_marked_new = splay_tree_new (splay_tree_compare_ints, 0, 0);
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;
186 info = XCNEW (struct ipa_dfs_info);
187 info->new_node = true;
188 info->on_stack = false;
189 info->next_cycle = NULL;
192 splay_tree_insert (env.nodes_marked_new,
193 (splay_tree_key)node->uid,
194 (splay_tree_value)node);
199 result = splay_tree_min (env.nodes_marked_new);
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);
209 return env.order_pos;
212 /* Deallocate all ipa_dfs_info structures pointed to by the aux pointer of call
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. */
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;
239 struct cgraph_edge *edge, last;
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)
251 for (pass = 0; pass < 2; pass++)
252 for (node = cgraph_nodes; node; node = node->next)
255 || (!node->address_taken
256 && !node->global.inlined_to
257 && !cgraph_only_called_directly_p (node))))
263 node->aux = node->callers;
266 while (node2->aux != &last)
268 edge = (struct cgraph_edge *) node2->aux;
269 if (edge->next_caller)
270 node2->aux = edge->next_caller;
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))
279 if (!edge->caller->aux)
281 if (!edge->caller->callers)
282 edge->caller->aux = &last;
284 edge->caller->aux = edge->caller->callers;
285 stack[stack_size++] = node2;
286 node2 = edge->caller;
290 if (node2->aux == &last)
292 order[order_pos++] = node2;
294 node2 = stack[--stack_size];
301 for (node = cgraph_nodes; node; node = node->next)
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
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);