Mercurial > hg > CbC > CbC_gcc
comparison gcc/graph.c @ 0:a06113de4d67
first commit
author | kent <kent@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2009 14:47:48 +0900 |
parents | |
children | f6334be47118 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a06113de4d67 |
---|---|
1 /* Output routines for graphical representation. | |
2 Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2007, 2008 | |
3 Free Software Foundation, Inc. | |
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. | |
5 | |
6 This file is part of GCC. | |
7 | |
8 GCC is free software; you can redistribute it and/or modify it under | |
9 the terms of the GNU General Public License as published by the Free | |
10 Software Foundation; either version 3, or (at your option) any later | |
11 version. | |
12 | |
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with GCC; see the file COPYING3. If not see | |
20 <http://www.gnu.org/licenses/>. */ | |
21 | |
22 #include <config.h> | |
23 #include "system.h" | |
24 #include "coretypes.h" | |
25 #include "tm.h" | |
26 #include "rtl.h" | |
27 #include "flags.h" | |
28 #include "output.h" | |
29 #include "function.h" | |
30 #include "hard-reg-set.h" | |
31 #include "obstack.h" | |
32 #include "basic-block.h" | |
33 #include "toplev.h" | |
34 #include "graph.h" | |
35 | |
36 static const char *const graph_ext[] = | |
37 { | |
38 /* no_graph */ "", | |
39 /* vcg */ ".vcg", | |
40 }; | |
41 | |
42 static void start_fct (FILE *); | |
43 static void start_bb (FILE *, int); | |
44 static void node_data (FILE *, rtx); | |
45 static void draw_edge (FILE *, int, int, int, int); | |
46 static void end_fct (FILE *); | |
47 static void end_bb (FILE *); | |
48 | |
49 /* Output text for new basic block. */ | |
50 static void | |
51 start_fct (FILE *fp) | |
52 { | |
53 switch (graph_dump_format) | |
54 { | |
55 case vcg: | |
56 fprintf (fp, "\ | |
57 graph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n", | |
58 current_function_name (), current_function_name ()); | |
59 break; | |
60 case no_graph: | |
61 break; | |
62 } | |
63 } | |
64 | |
65 static void | |
66 start_bb (FILE *fp, int bb) | |
67 { | |
68 #if 0 | |
69 reg_set_iterator rsi; | |
70 #endif | |
71 | |
72 switch (graph_dump_format) | |
73 { | |
74 case vcg: | |
75 fprintf (fp, "\ | |
76 graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\ | |
77 label: \"basic block %d", | |
78 current_function_name (), bb, bb); | |
79 break; | |
80 case no_graph: | |
81 break; | |
82 } | |
83 | |
84 #if 0 | |
85 /* FIXME Should this be printed? It makes the graph significantly larger. */ | |
86 | |
87 /* Print the live-at-start register list. */ | |
88 fputc ('\n', fp); | |
89 EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i, rsi) | |
90 { | |
91 fprintf (fp, " %d", i); | |
92 if (i < FIRST_PSEUDO_REGISTER) | |
93 fprintf (fp, " [%s]", reg_names[i]); | |
94 } | |
95 #endif | |
96 | |
97 switch (graph_dump_format) | |
98 { | |
99 case vcg: | |
100 fputs ("\"\n\n", fp); | |
101 break; | |
102 case no_graph: | |
103 break; | |
104 } | |
105 } | |
106 | |
107 static void | |
108 node_data (FILE *fp, rtx tmp_rtx) | |
109 { | |
110 if (PREV_INSN (tmp_rtx) == 0) | |
111 { | |
112 /* This is the first instruction. Add an edge from the starting | |
113 block. */ | |
114 switch (graph_dump_format) | |
115 { | |
116 case vcg: | |
117 fprintf (fp, "\ | |
118 edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n", | |
119 current_function_name (), | |
120 current_function_name (), XINT (tmp_rtx, 0)); | |
121 break; | |
122 case no_graph: | |
123 break; | |
124 } | |
125 } | |
126 | |
127 switch (graph_dump_format) | |
128 { | |
129 case vcg: | |
130 fprintf (fp, "node: {\n title: \"%s.%d\"\n color: %s\n \ | |
131 label: \"%s %d\n", | |
132 current_function_name (), XINT (tmp_rtx, 0), | |
133 NOTE_P (tmp_rtx) ? "lightgrey" | |
134 : NONJUMP_INSN_P (tmp_rtx) ? "green" | |
135 : JUMP_P (tmp_rtx) ? "darkgreen" | |
136 : CALL_P (tmp_rtx) ? "darkgreen" | |
137 : LABEL_P (tmp_rtx) ? "\ | |
138 darkgrey\n shape: ellipse" : "white", | |
139 GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0)); | |
140 break; | |
141 case no_graph: | |
142 break; | |
143 } | |
144 | |
145 /* Print the RTL. */ | |
146 if (NOTE_P (tmp_rtx)) | |
147 { | |
148 const char *name; | |
149 name = GET_NOTE_INSN_NAME (NOTE_KIND (tmp_rtx)); | |
150 fprintf (fp, " %s", name); | |
151 } | |
152 else if (INSN_P (tmp_rtx)) | |
153 print_rtl_single (fp, PATTERN (tmp_rtx)); | |
154 else | |
155 print_rtl_single (fp, tmp_rtx); | |
156 | |
157 switch (graph_dump_format) | |
158 { | |
159 case vcg: | |
160 fputs ("\"\n}\n", fp); | |
161 break; | |
162 case no_graph: | |
163 break; | |
164 } | |
165 } | |
166 | |
167 static void | |
168 draw_edge (FILE *fp, int from, int to, int bb_edge, int color_class) | |
169 { | |
170 const char * color; | |
171 switch (graph_dump_format) | |
172 { | |
173 case vcg: | |
174 color = ""; | |
175 if (color_class == 2) | |
176 color = "color: red "; | |
177 else if (bb_edge) | |
178 color = "color: blue "; | |
179 else if (color_class == 3) | |
180 color = "color: green "; | |
181 fprintf (fp, | |
182 "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s", | |
183 current_function_name (), from, | |
184 current_function_name (), to, color); | |
185 if (color_class) | |
186 fprintf (fp, "class: %d ", color_class); | |
187 fputs ("}\n", fp); | |
188 break; | |
189 case no_graph: | |
190 break; | |
191 } | |
192 } | |
193 | |
194 static void | |
195 end_bb (FILE *fp) | |
196 { | |
197 switch (graph_dump_format) | |
198 { | |
199 case vcg: | |
200 fputs ("}\n", fp); | |
201 break; | |
202 case no_graph: | |
203 break; | |
204 } | |
205 } | |
206 | |
207 static void | |
208 end_fct (FILE *fp) | |
209 { | |
210 switch (graph_dump_format) | |
211 { | |
212 case vcg: | |
213 fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n", | |
214 current_function_name ()); | |
215 break; | |
216 case no_graph: | |
217 break; | |
218 } | |
219 } | |
220 | |
221 /* Like print_rtl, but also print out live information for the start of each | |
222 basic block. */ | |
223 void | |
224 print_rtl_graph_with_bb (const char *base, rtx rtx_first) | |
225 { | |
226 rtx tmp_rtx; | |
227 size_t namelen = strlen (base); | |
228 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; | |
229 char *buf = XALLOCAVEC (char, namelen + extlen); | |
230 FILE *fp; | |
231 | |
232 if (basic_block_info == NULL) | |
233 return; | |
234 | |
235 memcpy (buf, base, namelen); | |
236 memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); | |
237 | |
238 fp = fopen (buf, "a"); | |
239 if (fp == NULL) | |
240 return; | |
241 | |
242 if (rtx_first == 0) | |
243 fprintf (fp, "(nil)\n"); | |
244 else | |
245 { | |
246 enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB }; | |
247 int max_uid = get_max_uid (); | |
248 int *start = XNEWVEC (int, max_uid); | |
249 int *end = XNEWVEC (int, max_uid); | |
250 enum bb_state *in_bb_p = XNEWVEC (enum bb_state, max_uid); | |
251 basic_block bb; | |
252 int i; | |
253 | |
254 for (i = 0; i < max_uid; ++i) | |
255 { | |
256 start[i] = end[i] = -1; | |
257 in_bb_p[i] = NOT_IN_BB; | |
258 } | |
259 | |
260 FOR_EACH_BB_REVERSE (bb) | |
261 { | |
262 rtx x; | |
263 start[INSN_UID (BB_HEAD (bb))] = bb->index; | |
264 end[INSN_UID (BB_END (bb))] = bb->index; | |
265 for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x)) | |
266 { | |
267 in_bb_p[INSN_UID (x)] | |
268 = (in_bb_p[INSN_UID (x)] == NOT_IN_BB) | |
269 ? IN_ONE_BB : IN_MULTIPLE_BB; | |
270 if (x == BB_END (bb)) | |
271 break; | |
272 } | |
273 } | |
274 | |
275 /* Tell print-rtl that we want graph output. */ | |
276 dump_for_graph = 1; | |
277 | |
278 /* Start new function. */ | |
279 start_fct (fp); | |
280 | |
281 for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx; | |
282 tmp_rtx = NEXT_INSN (tmp_rtx)) | |
283 { | |
284 int edge_printed = 0; | |
285 rtx next_insn; | |
286 | |
287 if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0) | |
288 { | |
289 if (BARRIER_P (tmp_rtx)) | |
290 continue; | |
291 if (NOTE_P (tmp_rtx) | |
292 && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB)) | |
293 continue; | |
294 } | |
295 | |
296 if ((i = start[INSN_UID (tmp_rtx)]) >= 0) | |
297 { | |
298 /* We start a subgraph for each basic block. */ | |
299 start_bb (fp, i); | |
300 | |
301 if (i == 0) | |
302 draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0); | |
303 } | |
304 | |
305 /* Print the data for this node. */ | |
306 node_data (fp, tmp_rtx); | |
307 next_insn = next_nonnote_insn (tmp_rtx); | |
308 | |
309 if ((i = end[INSN_UID (tmp_rtx)]) >= 0) | |
310 { | |
311 edge e; | |
312 edge_iterator ei; | |
313 | |
314 bb = BASIC_BLOCK (i); | |
315 | |
316 /* End of the basic block. */ | |
317 end_bb (fp); | |
318 | |
319 /* Now specify the edges to all the successors of this | |
320 basic block. */ | |
321 FOR_EACH_EDGE (e, ei, bb->succs) | |
322 { | |
323 if (e->dest != EXIT_BLOCK_PTR) | |
324 { | |
325 rtx block_head = BB_HEAD (e->dest); | |
326 | |
327 draw_edge (fp, INSN_UID (tmp_rtx), | |
328 INSN_UID (block_head), | |
329 next_insn != block_head, | |
330 (e->flags & EDGE_ABNORMAL ? 2 : 0)); | |
331 | |
332 if (block_head == next_insn) | |
333 edge_printed = 1; | |
334 } | |
335 else | |
336 { | |
337 draw_edge (fp, INSN_UID (tmp_rtx), 999999, | |
338 next_insn != 0, | |
339 (e->flags & EDGE_ABNORMAL ? 2 : 0)); | |
340 | |
341 if (next_insn == 0) | |
342 edge_printed = 1; | |
343 } | |
344 } | |
345 } | |
346 | |
347 if (!edge_printed) | |
348 { | |
349 /* Don't print edges to barriers. */ | |
350 if (next_insn == 0 | |
351 || !BARRIER_P (next_insn)) | |
352 draw_edge (fp, XINT (tmp_rtx, 0), | |
353 next_insn ? INSN_UID (next_insn) : 999999, 0, 0); | |
354 else | |
355 { | |
356 /* We draw the remaining edges in class 3. We have | |
357 to skip over the barrier since these nodes are | |
358 not printed at all. */ | |
359 do | |
360 next_insn = NEXT_INSN (next_insn); | |
361 while (next_insn | |
362 && (NOTE_P (next_insn) | |
363 || BARRIER_P (next_insn))); | |
364 | |
365 draw_edge (fp, XINT (tmp_rtx, 0), | |
366 next_insn ? INSN_UID (next_insn) : 999999, 0, 3); | |
367 } | |
368 } | |
369 } | |
370 | |
371 dump_for_graph = 0; | |
372 | |
373 end_fct (fp); | |
374 | |
375 /* Clean up. */ | |
376 free (start); | |
377 free (end); | |
378 free (in_bb_p); | |
379 } | |
380 | |
381 fclose (fp); | |
382 } | |
383 | |
384 | |
385 /* Similar as clean_dump_file, but this time for graph output files. */ | |
386 | |
387 void | |
388 clean_graph_dump_file (const char *base) | |
389 { | |
390 size_t namelen = strlen (base); | |
391 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; | |
392 char *buf = XALLOCAVEC (char, namelen + extlen); | |
393 FILE *fp; | |
394 | |
395 memcpy (buf, base, namelen); | |
396 memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); | |
397 | |
398 fp = fopen (buf, "w"); | |
399 | |
400 if (fp == NULL) | |
401 fatal_error ("can't open %s: %m", buf); | |
402 | |
403 gcc_assert (graph_dump_format == vcg); | |
404 fputs ("graph: {\nport_sharing: no\n", fp); | |
405 | |
406 fclose (fp); | |
407 } | |
408 | |
409 | |
410 /* Do final work on the graph output file. */ | |
411 void | |
412 finish_graph_dump_file (const char *base) | |
413 { | |
414 size_t namelen = strlen (base); | |
415 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; | |
416 char *buf = XALLOCAVEC (char, namelen + extlen); | |
417 FILE *fp; | |
418 | |
419 memcpy (buf, base, namelen); | |
420 memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); | |
421 | |
422 fp = fopen (buf, "a"); | |
423 if (fp != NULL) | |
424 { | |
425 gcc_assert (graph_dump_format == vcg); | |
426 fputs ("}\n", fp); | |
427 fclose (fp); | |
428 } | |
429 } |