]>
Commit | Line | Data |
---|---|---|
5489fcc3 KR |
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 | ||
12516a37 KR |
28 | typedef struct |
29 | { | |
5489fcc3 KR |
30 | Sym *sym; |
31 | int cycle_top; | |
12516a37 KR |
32 | } |
33 | DFN_Stack; | |
5489fcc3 KR |
34 | |
35 | DFN_Stack dfn_stack[DFN_DEPTH]; | |
12516a37 KR |
36 | int dfn_depth = 0; |
37 | int dfn_counter = DFN_NAN; | |
5489fcc3 KR |
38 | |
39 | ||
40 | /* | |
41 | * Is CHILD already numbered? | |
42 | */ | |
43 | static bool | |
12516a37 | 44 | DEFUN (is_numbered, (child), Sym * child) |
5489fcc3 | 45 | { |
12516a37 | 46 | return child->cg.top_order != DFN_NAN && child->cg.top_order != DFN_BUSY; |
03c35bcb | 47 | } |
5489fcc3 KR |
48 | |
49 | ||
50 | /* | |
51 | * Is CHILD already busy? | |
52 | */ | |
53 | static bool | |
12516a37 | 54 | DEFUN (is_busy, (child), Sym * child) |
5489fcc3 | 55 | { |
12516a37 KR |
56 | if (child->cg.top_order == DFN_NAN) |
57 | { | |
58 | return FALSE; | |
03c35bcb | 59 | } |
12516a37 | 60 | return TRUE; |
03c35bcb | 61 | } |
5489fcc3 KR |
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 | |
12516a37 | 71 | DEFUN (find_cycle, (child), Sym * child) |
5489fcc3 | 72 | { |
12516a37 KR |
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; | |
03c35bcb | 84 | } |
12516a37 KR |
85 | if (child->cg.cyc.head != child && child->cg.cyc.head == head) |
86 | { | |
87 | break; | |
03c35bcb KR |
88 | } |
89 | } | |
12516a37 KR |
90 | if (cycle_top <= 0) |
91 | { | |
92 | fprintf (stderr, "[find_cycle] couldn't find head of cycle\n"); | |
93 | done (1); | |
03c35bcb | 94 | } |
12516a37 KR |
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>"); | |
03c35bcb | 107 | } |
12516a37 KR |
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")); | |
03c35bcb | 140 | } |
12516a37 KR |
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")); | |
03c35bcb | 152 | } |
12516a37 KR |
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) | |
5489fcc3 | 170 | { |
12516a37 KR |
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")); | |
03c35bcb | 177 | } |
12516a37 KR |
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); | |
03c35bcb KR |
183 | } |
184 | } | |
185 | } | |
186 | } | |
5489fcc3 KR |
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 | |
12516a37 | 194 | DEFUN (pre_visit, (parent), Sym * parent) |
5489fcc3 | 195 | { |
12516a37 KR |
196 | ++dfn_depth; |
197 | if (dfn_depth >= DFN_DEPTH) | |
198 | { | |
199 | fprintf (stderr, "[pre_visit] dfn_stack overflow\n"); | |
200 | done (1); | |
03c35bcb | 201 | } |
12516a37 KR |
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")); | |
03c35bcb | 208 | } |
5489fcc3 KR |
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 | |
12516a37 | 216 | DEFUN (post_visit, (parent), Sym * parent) |
5489fcc3 | 217 | { |
12516a37 KR |
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)); | |
03c35bcb | 236 | } |
12516a37 KR |
237 | } |
238 | else | |
239 | { | |
240 | DBG (DFNDEBUG, printf ("[post_visit]\t\tis part of a cycle\n")); | |
03c35bcb | 241 | } |
12516a37 | 242 | --dfn_depth; |
03c35bcb | 243 | } |
5489fcc3 KR |
244 | |
245 | ||
246 | /* | |
247 | * Given this PARENT, depth first number its children. | |
248 | */ | |
249 | void | |
12516a37 | 250 | DEFUN (cg_dfn, (parent), Sym * parent) |
5489fcc3 | 251 | { |
12516a37 KR |
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; | |
03c35bcb | 263 | } |
12516a37 KR |
264 | /* |
265 | * If we're already busy, must be a cycle: | |
266 | */ | |
267 | if (is_busy (parent)) | |
268 | { | |
269 | find_cycle (parent); | |
270 | return; | |
03c35bcb | 271 | } |
12516a37 KR |
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); | |
03c35bcb | 279 | } |
12516a37 | 280 | post_visit (parent); |
03c35bcb | 281 | } |