Commit | Line | Data |
---|---|---|
252b5132 RH |
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 | */ | |
bd917ff6 | 19 | #include "libiberty.h" |
252b5132 | 20 | #include "gprof.h" |
6d9c411a AM |
21 | #include "search_list.h" |
22 | #include "source.h" | |
23 | #include "symtab.h" | |
252b5132 RH |
24 | #include "cg_arcs.h" |
25 | #include "cg_dfn.h" | |
252b5132 RH |
26 | #include "utils.h" |
27 | ||
bd917ff6 | 28 | #define DFN_INCR_DEPTH (128) |
252b5132 RH |
29 | |
30 | typedef struct | |
31 | { | |
32 | Sym *sym; | |
33 | int cycle_top; | |
34 | } | |
35 | DFN_Stack; | |
36 | ||
1355568a AM |
37 | static boolean is_numbered PARAMS ((Sym *)); |
38 | static boolean is_busy PARAMS ((Sym *)); | |
39 | static void find_cycle PARAMS ((Sym *)); | |
40 | static void pre_visit PARAMS ((Sym *)); | |
41 | static void post_visit PARAMS ((Sym *)); | |
42 | ||
bd917ff6 ILT |
43 | DFN_Stack *dfn_stack = NULL; |
44 | int dfn_maxdepth = 0; | |
252b5132 RH |
45 | int dfn_depth = 0; |
46 | int dfn_counter = DFN_NAN; | |
47 | ||
48 | ||
49 | /* | |
50 | * Is CHILD already numbered? | |
51 | */ | |
bde52789 | 52 | static boolean |
1355568a AM |
53 | is_numbered (child) |
54 | Sym *child; | |
252b5132 RH |
55 | { |
56 | return child->cg.top_order != DFN_NAN && child->cg.top_order != DFN_BUSY; | |
57 | } | |
58 | ||
59 | ||
60 | /* | |
61 | * Is CHILD already busy? | |
62 | */ | |
bde52789 | 63 | static boolean |
1355568a AM |
64 | is_busy (child) |
65 | Sym *child; | |
252b5132 RH |
66 | { |
67 | if (child->cg.top_order == DFN_NAN) | |
68 | { | |
bde52789 | 69 | return false; |
252b5132 | 70 | } |
bde52789 | 71 | return true; |
252b5132 RH |
72 | } |
73 | ||
74 | ||
75 | /* | |
76 | * CHILD is part of a cycle. Find the top caller into this cycle | |
77 | * that is not part of the cycle and make all functions in cycle | |
78 | * members of that cycle (top caller == caller with smallest | |
79 | * depth-first number). | |
80 | */ | |
81 | static void | |
1355568a AM |
82 | find_cycle (child) |
83 | Sym *child; | |
252b5132 RH |
84 | { |
85 | Sym *head = 0; | |
86 | Sym *tail; | |
87 | int cycle_top; | |
88 | int index; | |
89 | ||
90 | for (cycle_top = dfn_depth; cycle_top > 0; --cycle_top) | |
91 | { | |
92 | head = dfn_stack[cycle_top].sym; | |
93 | if (child == head) | |
94 | { | |
95 | break; | |
96 | } | |
97 | if (child->cg.cyc.head != child && child->cg.cyc.head == head) | |
98 | { | |
99 | break; | |
100 | } | |
101 | } | |
102 | if (cycle_top <= 0) | |
103 | { | |
104 | fprintf (stderr, "[find_cycle] couldn't find head of cycle\n"); | |
105 | done (1); | |
106 | } | |
107 | #ifdef DEBUG | |
108 | if (debug_level & DFNDEBUG) | |
109 | { | |
110 | printf ("[find_cycle] dfn_depth %d cycle_top %d ", | |
111 | dfn_depth, cycle_top); | |
112 | if (head) | |
113 | { | |
114 | print_name (head); | |
115 | } | |
116 | else | |
117 | { | |
118 | printf ("<unknown>"); | |
119 | } | |
120 | printf ("\n"); | |
121 | } | |
122 | #endif | |
123 | if (cycle_top == dfn_depth) | |
124 | { | |
125 | /* | |
126 | * This is previous function, e.g. this calls itself. Sort of | |
127 | * boring. | |
128 | * | |
129 | * Since we are taking out self-cycles elsewhere no need for | |
130 | * the special case, here. | |
131 | */ | |
132 | DBG (DFNDEBUG, | |
133 | printf ("[find_cycle] "); | |
134 | print_name (child); | |
135 | printf ("\n")); | |
136 | } | |
137 | else | |
138 | { | |
139 | /* | |
140 | * Glom intervening functions that aren't already glommed into | |
141 | * this cycle. Things have been glommed when their cyclehead | |
142 | * field points to the head of the cycle they are glommed | |
143 | * into. | |
144 | */ | |
145 | for (tail = head; tail->cg.cyc.next; tail = tail->cg.cyc.next) | |
146 | { | |
147 | /* void: chase down to tail of things already glommed */ | |
148 | DBG (DFNDEBUG, | |
149 | printf ("[find_cycle] tail "); | |
150 | print_name (tail); | |
151 | printf ("\n")); | |
152 | } | |
153 | /* | |
154 | * If what we think is the top of the cycle has a cyclehead | |
155 | * field, then it's not really the head of the cycle, which is | |
156 | * really what we want. | |
157 | */ | |
158 | if (head->cg.cyc.head != head) | |
159 | { | |
160 | head = head->cg.cyc.head; | |
161 | DBG (DFNDEBUG, printf ("[find_cycle] new cyclehead "); | |
162 | print_name (head); | |
163 | printf ("\n")); | |
164 | } | |
165 | for (index = cycle_top + 1; index <= dfn_depth; ++index) | |
166 | { | |
167 | child = dfn_stack[index].sym; | |
168 | if (child->cg.cyc.head == child) | |
169 | { | |
170 | /* | |
171 | * Not yet glommed anywhere, glom it and fix any | |
172 | * children it has glommed. | |
173 | */ | |
174 | tail->cg.cyc.next = child; | |
175 | child->cg.cyc.head = head; | |
176 | DBG (DFNDEBUG, printf ("[find_cycle] glomming "); | |
177 | print_name (child); | |
178 | printf (" onto "); | |
179 | print_name (head); | |
180 | printf ("\n")); | |
181 | for (tail = child; tail->cg.cyc.next; tail = tail->cg.cyc.next) | |
182 | { | |
183 | tail->cg.cyc.next->cg.cyc.head = head; | |
184 | DBG (DFNDEBUG, printf ("[find_cycle] and its tail "); | |
185 | print_name (tail->cg.cyc.next); | |
186 | printf (" onto "); | |
187 | print_name (head); | |
188 | printf ("\n")); | |
189 | } | |
190 | } | |
191 | else if (child->cg.cyc.head != head /* firewall */ ) | |
192 | { | |
193 | fprintf (stderr, "[find_cycle] glommed, but not to head\n"); | |
194 | done (1); | |
195 | } | |
196 | } | |
197 | } | |
198 | } | |
199 | ||
200 | ||
201 | /* | |
202 | * Prepare for visiting the children of PARENT. Push a parent onto | |
203 | * the stack and mark it busy. | |
204 | */ | |
205 | static void | |
1355568a AM |
206 | pre_visit (parent) |
207 | Sym *parent; | |
252b5132 RH |
208 | { |
209 | ++dfn_depth; | |
bd917ff6 ILT |
210 | |
211 | if (dfn_depth >= dfn_maxdepth) | |
252b5132 | 212 | { |
bd917ff6 ILT |
213 | dfn_maxdepth += DFN_INCR_DEPTH; |
214 | dfn_stack = xrealloc (dfn_stack, dfn_maxdepth * sizeof *dfn_stack); | |
252b5132 | 215 | } |
bd917ff6 | 216 | |
252b5132 RH |
217 | dfn_stack[dfn_depth].sym = parent; |
218 | dfn_stack[dfn_depth].cycle_top = dfn_depth; | |
219 | parent->cg.top_order = DFN_BUSY; | |
220 | DBG (DFNDEBUG, printf ("[pre_visit]\t\t%d:", dfn_depth); | |
221 | print_name (parent); | |
222 | printf ("\n")); | |
223 | } | |
224 | ||
225 | ||
226 | /* | |
227 | * Done with visiting node PARENT. Pop PARENT off dfn_stack | |
228 | * and number functions if PARENT is head of a cycle. | |
229 | */ | |
230 | static void | |
1355568a AM |
231 | post_visit (parent) |
232 | Sym *parent; | |
252b5132 RH |
233 | { |
234 | Sym *member; | |
235 | ||
236 | DBG (DFNDEBUG, printf ("[post_visit]\t%d: ", dfn_depth); | |
237 | print_name (parent); | |
238 | printf ("\n")); | |
239 | /* | |
240 | * Number functions and things in their cycles unless the function | |
241 | * is itself part of a cycle: | |
242 | */ | |
243 | if (parent->cg.cyc.head == parent) | |
244 | { | |
245 | ++dfn_counter; | |
246 | for (member = parent; member; member = member->cg.cyc.next) | |
247 | { | |
248 | member->cg.top_order = dfn_counter; | |
249 | DBG (DFNDEBUG, printf ("[post_visit]\t\tmember "); | |
250 | print_name (member); | |
251 | printf ("-> cg.top_order = %d\n", dfn_counter)); | |
252 | } | |
253 | } | |
254 | else | |
255 | { | |
256 | DBG (DFNDEBUG, printf ("[post_visit]\t\tis part of a cycle\n")); | |
257 | } | |
258 | --dfn_depth; | |
259 | } | |
260 | ||
261 | ||
262 | /* | |
263 | * Given this PARENT, depth first number its children. | |
264 | */ | |
265 | void | |
1355568a AM |
266 | cg_dfn (parent) |
267 | Sym *parent; | |
252b5132 RH |
268 | { |
269 | Arc *arc; | |
270 | ||
271 | DBG (DFNDEBUG, printf ("[dfn] dfn( "); | |
272 | print_name (parent); | |
273 | printf (")\n")); | |
274 | /* | |
275 | * If we're already numbered, no need to look any further: | |
276 | */ | |
277 | if (is_numbered (parent)) | |
278 | { | |
279 | return; | |
280 | } | |
281 | /* | |
282 | * If we're already busy, must be a cycle: | |
283 | */ | |
284 | if (is_busy (parent)) | |
285 | { | |
286 | find_cycle (parent); | |
287 | return; | |
288 | } | |
289 | pre_visit (parent); | |
290 | /* | |
291 | * Recursively visit children: | |
292 | */ | |
293 | for (arc = parent->cg.children; arc; arc = arc->next_child) | |
294 | { | |
295 | cg_dfn (arc->child); | |
296 | } | |
297 | post_visit (parent); | |
298 | } |