Mon Mar 17 10:54:47 1997 David Mosberger-Tang <davidm@azstarnet.com>
[external/binutils.git] / gprof / cg_dfn.c
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that: (1) source distributions retain this entire copyright
7  * notice and comment, and (2) distributions including binaries display
8  * the following acknowledgement:  ``This product includes software
9  * developed by the University of California, Berkeley and its contributors''
10  * in the documentation or other materials provided with the distribution
11  * and in all advertising materials mentioning features or use of this
12  * software. Neither the name of the University nor the names of its
13  * contributors may be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  */
19 #include <stdio.h>
20 #include "gprof.h"
21 #include "cg_arcs.h"
22 #include "cg_dfn.h"
23 #include "symtab.h"
24 #include "utils.h"
25
26 #define DFN_DEPTH       100
27
28 typedef struct
29   {
30     Sym *sym;
31     int cycle_top;
32   }
33 DFN_Stack;
34
35 DFN_Stack dfn_stack[DFN_DEPTH];
36 int dfn_depth = 0;
37 int dfn_counter = DFN_NAN;
38
39
40 /*
41  * Is CHILD already numbered?
42  */
43 static bool
44 DEFUN (is_numbered, (child), Sym * child)
45 {
46   return child->cg.top_order != DFN_NAN && child->cg.top_order != DFN_BUSY;
47 }
48
49
50 /*
51  * Is CHILD already busy?
52  */
53 static bool
54 DEFUN (is_busy, (child), Sym * child)
55 {
56   if (child->cg.top_order == DFN_NAN)
57     {
58       return FALSE;
59     }
60   return TRUE;
61 }
62
63
64 /*
65  * CHILD is part of a cycle.  Find the top caller into this cycle
66  * that is not part of the cycle and make all functions in cycle
67  * members of that cycle (top caller == caller with smallest
68  * depth-first number).
69  */
70 static void
71 DEFUN (find_cycle, (child), Sym * child)
72 {
73   Sym *head = 0;
74   Sym *tail;
75   int cycle_top;
76   int index;
77
78   for (cycle_top = dfn_depth; cycle_top > 0; --cycle_top)
79     {
80       head = dfn_stack[cycle_top].sym;
81       if (child == head)
82         {
83           break;
84         }
85       if (child->cg.cyc.head != child && child->cg.cyc.head == head)
86         {
87           break;
88         }
89     }
90   if (cycle_top <= 0)
91     {
92       fprintf (stderr, "[find_cycle] couldn't find head of cycle\n");
93       done (1);
94     }
95 #ifdef DEBUG
96   if (debug_level & DFNDEBUG)
97     {
98       printf ("[find_cycle] dfn_depth %d cycle_top %d ",
99               dfn_depth, cycle_top);
100       if (head)
101         {
102           print_name (head);
103         }
104       else
105         {
106           printf ("<unknown>");
107         }
108       printf ("\n");
109     }
110 #endif
111   if (cycle_top == dfn_depth)
112     {
113       /*
114        * This is previous function, e.g. this calls itself.  Sort of
115        * boring.
116        *
117        * Since we are taking out self-cycles elsewhere no need for
118        * the special case, here.
119        */
120       DBG (DFNDEBUG,
121            printf ("[find_cycle] ");
122            print_name (child);
123            printf ("\n"));
124     }
125   else
126     {
127       /*
128        * Glom intervening functions that aren't already glommed into
129        * this cycle.  Things have been glommed when their cyclehead
130        * field points to the head of the cycle they are glommed
131        * into.
132        */
133       for (tail = head; tail->cg.cyc.next; tail = tail->cg.cyc.next)
134         {
135           /* void: chase down to tail of things already glommed */
136           DBG (DFNDEBUG,
137                printf ("[find_cycle] tail ");
138                print_name (tail);
139                printf ("\n"));
140         }
141       /*
142        * If what we think is the top of the cycle has a cyclehead
143        * field, then it's not really the head of the cycle, which is
144        * really what we want.
145        */
146       if (head->cg.cyc.head != head)
147         {
148           head = head->cg.cyc.head;
149           DBG (DFNDEBUG, printf ("[find_cycle] new cyclehead ");
150                print_name (head);
151                printf ("\n"));
152         }
153       for (index = cycle_top + 1; index <= dfn_depth; ++index)
154         {
155           child = dfn_stack[index].sym;
156           if (child->cg.cyc.head == child)
157             {
158               /*
159                * Not yet glommed anywhere, glom it and fix any
160                * children it has glommed.
161                */
162               tail->cg.cyc.next = child;
163               child->cg.cyc.head = head;
164               DBG (DFNDEBUG, printf ("[find_cycle] glomming ");
165                    print_name (child);
166                    printf (" onto ");
167                    print_name (head);
168                    printf ("\n"));
169               for (tail = child; tail->cg.cyc.next; tail = tail->cg.cyc.next)
170                 {
171                   tail->cg.cyc.next->cg.cyc.head = head;
172                   DBG (DFNDEBUG, printf ("[find_cycle] and its tail ");
173                        print_name (tail->cg.cyc.next);
174                        printf (" onto ");
175                        print_name (head);
176                        printf ("\n"));
177                 }
178             }
179           else if (child->cg.cyc.head != head /* firewall */ )
180             {
181               fprintf (stderr, "[find_cycle] glommed, but not to head\n");
182               done (1);
183             }
184         }
185     }
186 }
187
188
189 /*
190  * Prepare for visiting the children of PARENT.  Push a parent onto
191  * the stack and mark it busy.
192  */
193 static void
194 DEFUN (pre_visit, (parent), Sym * parent)
195 {
196   ++dfn_depth;
197   if (dfn_depth >= DFN_DEPTH)
198     {
199       fprintf (stderr, "[pre_visit] dfn_stack overflow\n");
200       done (1);
201     }
202   dfn_stack[dfn_depth].sym = parent;
203   dfn_stack[dfn_depth].cycle_top = dfn_depth;
204   parent->cg.top_order = DFN_BUSY;
205   DBG (DFNDEBUG, printf ("[pre_visit]\t\t%d:", dfn_depth);
206        print_name (parent);
207        printf ("\n"));
208 }
209
210
211 /*
212  * Done with visiting node PARENT.  Pop PARENT off dfn_stack
213  * and number functions if PARENT is head of a cycle.
214  */
215 static void
216 DEFUN (post_visit, (parent), Sym * parent)
217 {
218   Sym *member;
219
220   DBG (DFNDEBUG, printf ("[post_visit]\t%d: ", dfn_depth);
221        print_name (parent);
222        printf ("\n"));
223   /*
224    * Number functions and things in their cycles unless the function
225    * is itself part of a cycle:
226    */
227   if (parent->cg.cyc.head == parent)
228     {
229       ++dfn_counter;
230       for (member = parent; member; member = member->cg.cyc.next)
231         {
232           member->cg.top_order = dfn_counter;
233           DBG (DFNDEBUG, printf ("[post_visit]\t\tmember ");
234                print_name (member);
235                printf ("-> cg.top_order = %d\n", dfn_counter));
236         }
237     }
238   else
239     {
240       DBG (DFNDEBUG, printf ("[post_visit]\t\tis part of a cycle\n"));
241     }
242   --dfn_depth;
243 }
244
245
246 /*
247  * Given this PARENT, depth first number its children.
248  */
249 void
250 DEFUN (cg_dfn, (parent), Sym * parent)
251 {
252   Arc *arc;
253
254   DBG (DFNDEBUG, printf ("[dfn] dfn( ");
255        print_name (parent);
256        printf (")\n"));
257   /*
258    * If we're already numbered, no need to look any further:
259    */
260   if (is_numbered (parent))
261     {
262       return;
263     }
264   /*
265    * If we're already busy, must be a cycle:
266    */
267   if (is_busy (parent))
268     {
269       find_cycle (parent);
270       return;
271     }
272   pre_visit (parent);
273   /*
274    * Recursively visit children:
275    */
276   for (arc = parent->cg.children; arc; arc = arc->next_child)
277     {
278       cg_dfn (arc->child);
279     }
280   post_visit (parent);
281 }