]> gcc.gnu.org Git - gcc.git/blame - gcc/ipa-utils.c
* MAINTAINERS: Update my email address.
[gcc.git] / gcc / ipa-utils.c
CommitLineData
ea900239 1/* Utilities for ipa analysis.
66647d44 2 Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
ea900239
DB
3 Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9dcd6f09 9Software Foundation; either version 3, or (at your option) any later
ea900239
DB
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
9dcd6f09
NC
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
ea900239
DB
20
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"
ea264ca5 31#include "splay-tree.h"
ea900239
DB
32#include "ggc.h"
33#include "ipa-utils.h"
34#include "ipa-reference.h"
726a989a 35#include "gimple.h"
ea900239
DB
36#include "cgraph.h"
37#include "output.h"
38#include "flags.h"
39#include "timevar.h"
40#include "diagnostic.h"
41#include "langhooks.h"
42
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. */
46
b8698a0f 47void
af8bca3c
MJ
48ipa_print_order (FILE* out,
49 const char * note,
50 struct cgraph_node** order,
51 int count)
ea900239
DB
52{
53 int i;
54 fprintf (out, "\n\n ordered call graph: %s\n", note);
b8698a0f 55
ea900239
DB
56 for (i = count - 1; i >= 0; i--)
57 dump_cgraph_node(dump_file, order[i]);
58 fprintf (out, "\n");
59 fflush(out);
60}
61
62\f
63struct 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;
71};
72
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
af8bca3c 79 ipa_reduced_postorder. ENV is a stack env and would be
ea900239
DB
80 unnecessary if C had nested functions. V is the node to start
81 searching from. */
82
83static void
2505c5ed
JH
84searchc (struct searchc_env* env, struct cgraph_node *v,
85 bool (*ignore_edge) (struct cgraph_edge *))
ea900239
DB
86{
87 struct cgraph_edge *edge;
c5274326 88 struct ipa_dfs_info *v_info = (struct ipa_dfs_info *) v->aux;
b8698a0f 89
ea900239 90 /* mark node as old */
c5274326 91 v_info->new_node = false;
ea900239 92 splay_tree_remove (env->nodes_marked_new, v->uid);
b8698a0f 93
ea900239
DB
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;
b8698a0f 99
ea900239
DB
100 for (edge = v->callees; edge; edge = edge->next_callee)
101 {
102 struct ipa_dfs_info * w_info;
103 struct cgraph_node *w = edge->callee;
e2c9111c 104
2505c5ed
JH
105 if (ignore_edge && ignore_edge (edge))
106 continue;
107
e2c9111c 108 if (w->aux && cgraph_function_body_availability (edge->callee) > AVAIL_OVERWRITABLE)
ea900239 109 {
c5274326 110 w_info = (struct ipa_dfs_info *) w->aux;
b8698a0f 111 if (w_info->new_node)
ea900239 112 {
2505c5ed 113 searchc (env, w, ignore_edge);
ea900239
DB
114 v_info->low_link =
115 (v_info->low_link < w_info->low_link) ?
116 v_info->low_link : w_info->low_link;
b8698a0f
L
117 }
118 else
119 if ((w_info->dfn_number < v_info->dfn_number)
120 && (w_info->on_stack))
ea900239
DB
121 v_info->low_link =
122 (w_info->dfn_number < v_info->low_link) ?
123 w_info->dfn_number : v_info->low_link;
124 }
125 }
126
127
b8698a0f 128 if (v_info->low_link == v_info->dfn_number)
ea900239
DB
129 {
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)];
c5274326 135 x_info = (struct ipa_dfs_info *) x->aux;
ea900239 136 x_info->on_stack = false;
b8698a0f
L
137
138 if (env->reduce)
ea900239
DB
139 {
140 x_info->next_cycle = last;
141 last = x;
b8698a0f
L
142 }
143 else
ea900239 144 env->result[env->order_pos++] = x;
b8698a0f 145 }
ea900239 146 while (v != x);
b8698a0f 147 if (env->reduce)
ea900239
DB
148 env->result[env->order_pos++] = v;
149 }
150}
151
152/* Topsort the call graph by caller relation. Put the result in ORDER.
153
af8bca3c
MJ
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. */
ea900239
DB
158
159int
af8bca3c
MJ
160ipa_reduced_postorder (struct cgraph_node **order,
161 bool reduce, bool allow_overwritable,
162 bool (*ignore_edge) (struct cgraph_edge *))
ea900239
DB
163{
164 struct cgraph_node *node;
165 struct searchc_env env;
166 splay_tree_node result;
5ed6ace5 167 env.stack = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
ea900239
DB
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;
b8698a0f
L
174
175 for (node = cgraph_nodes; node; node = node->next)
e2c9111c
JH
176 {
177 enum availability avail = cgraph_function_body_availability (node);
178
179 if (avail > AVAIL_OVERWRITABLE
b8698a0f 180 || (allow_overwritable
e2c9111c
JH
181 && (avail == AVAIL_OVERWRITABLE)))
182 {
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;
b8698a0f 191
e2c9111c 192 splay_tree_insert (env.nodes_marked_new,
b8698a0f 193 (splay_tree_key)node->uid,
e2c9111c 194 (splay_tree_value)node);
b8698a0f
L
195 }
196 else
e2c9111c
JH
197 node->aux = NULL;
198 }
ea900239
DB
199 result = splay_tree_min (env.nodes_marked_new);
200 while (result)
201 {
202 node = (struct cgraph_node *)result->value;
2505c5ed 203 searchc (&env, node, ignore_edge);
ea900239
DB
204 result = splay_tree_min (env.nodes_marked_new);
205 }
206 splay_tree_delete (env.nodes_marked_new);
207 free (env.stack);
208
209 return env.order_pos;
210}
211
af8bca3c
MJ
212/* Deallocate all ipa_dfs_info structures pointed to by the aux pointer of call
213 graph nodes. */
214
215void
216ipa_free_postorder_info (void)
217{
218 struct cgraph_node *node;
219 for (node = cgraph_nodes; node; node = node->next)
220 {
221 /* Get rid of the aux information. */
222 if (node->aux)
223 {
224 free (node->aux);
225 node->aux = NULL;
226 }
227 }
228}
229
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. */
232
233int
234ipa_reverse_postorder (struct cgraph_node **order)
235{
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;
241
242 struct cgraph_node **stack =
243 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
244
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))))
258 {
259 node2 = node;
260 if (!node->callers)
261 node->aux = &last;
262 else
263 node->aux = node->callers;
264 while (node2)
265 {
266 while (node2->aux != &last)
267 {
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)
280 {
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;
288 }
289 }
290 if (node2->aux == &last)
291 {
292 order[order_pos++] = node2;
293 if (stack_size)
294 node2 = stack[--stack_size];
295 else
296 node2 = NULL;
297 }
298 }
299 }
300 free (stack);
301 for (node = cgraph_nodes; node; node = node->next)
302 node->aux = NULL;
303 return order_pos;
304}
305
306
ea900239
DB
307
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. */
311
312tree
313get_base_var (tree t)
314{
b8698a0f 315 while (!SSA_VAR_P (t)
ea900239
DB
316 && (!CONSTANT_CLASS_P (t))
317 && TREE_CODE (t) != LABEL_DECL
318 && TREE_CODE (t) != FUNCTION_DECL
3baf459d
DN
319 && TREE_CODE (t) != CONST_DECL
320 && TREE_CODE (t) != CONSTRUCTOR)
ea900239
DB
321 {
322 t = TREE_OPERAND (t, 0);
323 }
324 return t;
b8698a0f 325}
ea900239 326
1cb1a99f
JH
327
328/* Create a new cgraph node set. */
329
330cgraph_node_set
331cgraph_node_set_new (void)
332{
333 cgraph_node_set new_node_set;
334
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;
339}
340
341
342/* Add cgraph_node NODE to cgraph_node_set SET. */
343
344void
345cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
346{
347 void **slot;
348
349 slot = pointer_map_insert (set->map, node);
350
351 if (*slot)
352 {
353 int index = (size_t) *slot - 1;
354 gcc_checking_assert ((VEC_index (cgraph_node_ptr, set->nodes, index)
355 == node));
356 return;
357 }
358
359 *slot = (void *)(size_t) (VEC_length (cgraph_node_ptr, set->nodes) + 1);
360
361 /* Insert into node vector. */
362 VEC_safe_push (cgraph_node_ptr, heap, set->nodes, node);
363}
364
365
366/* Remove cgraph_node NODE from cgraph_node_set SET. */
367
368void
369cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
370{
371 void **slot, **last_slot;
372 int index;
373 struct cgraph_node *last_node;
374
375 slot = pointer_map_contains (set->map, node);
376 if (slot == NULL || !*slot)
377 return;
378
379 index = (size_t) *slot - 1;
380 gcc_checking_assert (VEC_index (cgraph_node_ptr, set->nodes, index)
381 == node);
382
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)
387 {
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);
391
392 /* Move the last element to the original spot of NODE. */
393 VEC_replace (cgraph_node_ptr, set->nodes, index, last_node);
394 }
395
396 /* Remove element from hash table. */
397 *slot = NULL;
398}
399
400
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. */
403
404cgraph_node_set_iterator
405cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
406{
407 void **slot;
408 cgraph_node_set_iterator csi;
409
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;
416
417 return csi;
418}
419
420
421/* Dump content of SET to file F. */
422
423void
424dump_cgraph_node_set (FILE *f, cgraph_node_set set)
425{
426 cgraph_node_set_iterator iter;
427
428 for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
429 {
430 struct cgraph_node *node = csi_node (iter);
431 fprintf (f, " %s/%i", cgraph_node_name (node), node->uid);
432 }
433 fprintf (f, "\n");
434}
435
436
437/* Dump content of SET to stderr. */
438
439DEBUG_FUNCTION void
440debug_cgraph_node_set (cgraph_node_set set)
441{
442 dump_cgraph_node_set (stderr, set);
443}
444
445
446/* Free varpool node set. */
447
448void
449free_cgraph_node_set (cgraph_node_set set)
450{
451 VEC_free (cgraph_node_ptr, heap, set->nodes);
452 pointer_map_destroy (set->map);
453 free (set);
454}
455
456
457/* Create a new varpool node set. */
458
459varpool_node_set
460varpool_node_set_new (void)
461{
462 varpool_node_set new_node_set;
463
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;
468}
469
470
471/* Add varpool_node NODE to varpool_node_set SET. */
472
473void
474varpool_node_set_add (varpool_node_set set, struct varpool_node *node)
475{
476 void **slot;
477
478 slot = pointer_map_insert (set->map, node);
479
480 if (*slot)
481 {
482 int index = (size_t) *slot - 1;
483 gcc_checking_assert ((VEC_index (varpool_node_ptr, set->nodes, index)
484 == node));
485 return;
486 }
487
488 *slot = (void *)(size_t) (VEC_length (varpool_node_ptr, set->nodes) + 1);
489
490 /* Insert into node vector. */
491 VEC_safe_push (varpool_node_ptr, heap, set->nodes, node);
492}
493
494
495/* Remove varpool_node NODE from varpool_node_set SET. */
496
497void
498varpool_node_set_remove (varpool_node_set set, struct varpool_node *node)
499{
500 void **slot, **last_slot;
501 int index;
502 struct varpool_node *last_node;
503
504 slot = pointer_map_contains (set->map, node);
505 if (slot == NULL || !*slot)
506 return;
507
508 index = (size_t) *slot - 1;
509 gcc_checking_assert (VEC_index (varpool_node_ptr, set->nodes, index)
510 == node);
511
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)
516 {
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);
520
521 /* Move the last element to the original spot of NODE. */
522 VEC_replace (varpool_node_ptr, set->nodes, index, last_node);
523 }
524
525 /* Remove element from hash table. */
526 *slot = NULL;
527}
528
529
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. */
532
533varpool_node_set_iterator
534varpool_node_set_find (varpool_node_set set, struct varpool_node *node)
535{
536 void **slot;
537 varpool_node_set_iterator vsi;
538
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;
545
546 return vsi;
547}
548
549
550/* Dump content of SET to file F. */
551
552void
553dump_varpool_node_set (FILE *f, varpool_node_set set)
554{
555 varpool_node_set_iterator iter;
556
557 for (iter = vsi_start (set); !vsi_end_p (iter); vsi_next (&iter))
558 {
559 struct varpool_node *node = vsi_node (iter);
560 fprintf (f, " %s", varpool_node_name (node));
561 }
562 fprintf (f, "\n");
563}
564
565
566/* Free varpool node set. */
567
568void
569free_varpool_node_set (varpool_node_set set)
570{
571 VEC_free (varpool_node_ptr, heap, set->nodes);
572 pointer_map_destroy (set->map);
573 free (set);
574}
575
576
577/* Dump content of SET to stderr. */
578
579DEBUG_FUNCTION void
580debug_varpool_node_set (varpool_node_set set)
581{
582 dump_varpool_node_set (stderr, set);
583}
This page took 2.062326 seconds and 5 git commands to generate.