FSF GCC merge 02/23/03
[official-gcc.git] / gcc / graph.c
blobe56ef93809fe2937b8b8bc7936650555d94665ef
1 /* Output routines for graphical representation.
2 Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
22 #include <config.h>
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
27 #include "rtl.h"
28 #include "flags.h"
29 #include "output.h"
30 #include "function.h"
31 #include "hard-reg-set.h"
32 #include "basic-block.h"
33 #include "toplev.h"
34 #include "graph.h"
36 static const char *const graph_ext[] =
38 /* no_graph */ "",
39 /* vcg */ ".vcg",
42 static void start_fct PARAMS ((FILE *));
43 static void start_bb PARAMS ((FILE *, int));
44 static void node_data PARAMS ((FILE *, rtx));
45 static void draw_edge PARAMS ((FILE *, int, int, int, int));
46 static void end_fct PARAMS ((FILE *));
47 static void end_bb PARAMS ((FILE *));
49 /* Output text for new basic block. */
50 static void
51 start_fct (fp)
52 FILE *fp;
55 switch (graph_dump_format)
57 case vcg:
58 fprintf (fp, "\
59 graph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n",
60 current_function_name, current_function_name);
61 break;
62 case no_graph:
63 break;
67 static void
68 start_bb (fp, bb)
69 FILE *fp;
70 int bb;
72 switch (graph_dump_format)
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;
84 #if 0
85 /* FIXME Should this be printed? It makes the graph significantly larger. */
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,
91 fprintf (fp, " %d", i);
92 if (i < FIRST_PSEUDO_REGISTER)
93 fprintf (fp, " [%s]",
94 reg_names[i]);
95 });
96 #endif
98 switch (graph_dump_format)
100 case vcg:
101 fputs ("\"\n\n", fp);
102 break;
103 case no_graph:
104 break;
108 static void
109 node_data (fp, tmp_rtx)
110 FILE *fp;
111 rtx tmp_rtx;
114 if (PREV_INSN (tmp_rtx) == 0)
116 /* This is the first instruction. Add an edge from the starting
117 block. */
118 switch (graph_dump_format)
120 case vcg:
121 fprintf (fp, "\
122 edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n",
123 current_function_name,
124 current_function_name, XINT (tmp_rtx, 0));
125 break;
126 case no_graph:
127 break;
131 switch (graph_dump_format)
133 case vcg:
134 fprintf (fp, "node: {\n title: \"%s.%d\"\n color: %s\n \
135 label: \"%s %d\n",
136 current_function_name, XINT (tmp_rtx, 0),
137 GET_CODE (tmp_rtx) == NOTE ? "lightgrey"
138 : GET_CODE (tmp_rtx) == INSN ? "green"
139 : GET_CODE (tmp_rtx) == JUMP_INSN ? "darkgreen"
140 : GET_CODE (tmp_rtx) == CALL_INSN ? "darkgreen"
141 : GET_CODE (tmp_rtx) == CODE_LABEL ? "\
142 darkgrey\n shape: ellipse" : "white",
143 GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0));
144 break;
145 case no_graph:
146 break;
149 /* Print the RTL. */
150 if (GET_CODE (tmp_rtx) == NOTE)
152 const char *name = "";
153 if (NOTE_LINE_NUMBER (tmp_rtx) < 0)
154 name = GET_NOTE_INSN_NAME (NOTE_LINE_NUMBER (tmp_rtx));
155 fprintf (fp, " %s", name);
157 else if (INSN_P (tmp_rtx))
158 print_rtl_single (fp, PATTERN (tmp_rtx));
159 else
160 print_rtl_single (fp, tmp_rtx);
162 switch (graph_dump_format)
164 case vcg:
165 fputs ("\"\n}\n", fp);
166 break;
167 case no_graph:
168 break;
172 static void
173 draw_edge (fp, from, to, bb_edge, class)
174 FILE *fp;
175 int from;
176 int to;
177 int bb_edge;
178 int class;
180 const char * color;
181 switch (graph_dump_format)
183 case vcg:
184 color = "";
185 if (class == 2)
186 color = "color: red ";
187 else if (bb_edge)
188 color = "color: blue ";
189 else if (class == 3)
190 color = "color: green ";
191 fprintf (fp,
192 "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
193 current_function_name, from,
194 current_function_name, to, color);
195 if (class)
196 fprintf (fp, "class: %d ", class);
197 fputs ("}\n", fp);
198 break;
199 case no_graph:
200 break;
204 static void
205 end_bb (fp)
206 FILE *fp;
208 switch (graph_dump_format)
210 case vcg:
211 fputs ("}\n", fp);
212 break;
213 case no_graph:
214 break;
218 static void
219 end_fct (fp)
220 FILE *fp;
222 switch (graph_dump_format)
224 case vcg:
225 fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n",
226 current_function_name);
227 break;
228 case no_graph:
229 break;
233 /* Like print_rtl, but also print out live information for the start of each
234 basic block. */
235 void
236 print_rtl_graph_with_bb (base, suffix, rtx_first)
237 const char *base;
238 const char *suffix;
239 rtx rtx_first;
241 rtx tmp_rtx;
242 size_t namelen = strlen (base);
243 size_t suffixlen = strlen (suffix);
244 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
245 char *buf = (char *) alloca (namelen + suffixlen + extlen);
246 FILE *fp;
248 if (basic_block_info == NULL)
249 return;
251 memcpy (buf, base, namelen);
252 memcpy (buf + namelen, suffix, suffixlen);
253 memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
255 fp = fopen (buf, "a");
256 if (fp == NULL)
257 return;
259 if (rtx_first == 0)
260 fprintf (fp, "(nil)\n");
261 else
263 enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
264 int max_uid = get_max_uid ();
265 int *start = (int *) xmalloc (max_uid * sizeof (int));
266 int *end = (int *) xmalloc (max_uid * sizeof (int));
267 enum bb_state *in_bb_p = (enum bb_state *)
268 xmalloc (max_uid * sizeof (enum bb_state));
269 basic_block bb;
270 int i;
272 for (i = 0; i < max_uid; ++i)
274 start[i] = end[i] = -1;
275 in_bb_p[i] = NOT_IN_BB;
278 FOR_EACH_BB_REVERSE (bb)
280 rtx x;
281 start[INSN_UID (bb->head)] = bb->index;
282 end[INSN_UID (bb->end)] = bb->index;
283 for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x))
285 in_bb_p[INSN_UID (x)]
286 = (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
287 ? IN_ONE_BB : IN_MULTIPLE_BB;
288 if (x == bb->end)
289 break;
293 /* Tell print-rtl that we want graph output. */
294 dump_for_graph = 1;
296 /* Start new function. */
297 start_fct (fp);
299 for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx;
300 tmp_rtx = NEXT_INSN (tmp_rtx))
302 int edge_printed = 0;
303 rtx next_insn;
305 if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
307 if (GET_CODE (tmp_rtx) == BARRIER)
308 continue;
309 if (GET_CODE (tmp_rtx) == NOTE
310 && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB))
311 continue;
314 if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
316 /* We start a subgraph for each basic block. */
317 start_bb (fp, i);
319 if (i == 0)
320 draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
323 /* Print the data for this node. */
324 node_data (fp, tmp_rtx);
325 next_insn = next_nonnote_insn (tmp_rtx);
327 if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
329 edge e;
331 bb = BASIC_BLOCK (i);
333 /* End of the basic block. */
334 end_bb (fp);
336 /* Now specify the edges to all the successors of this
337 basic block. */
338 for (e = bb->succ; e ; e = e->succ_next)
340 if (e->dest != EXIT_BLOCK_PTR)
342 rtx block_head = e->dest->head;
344 draw_edge (fp, INSN_UID (tmp_rtx),
345 INSN_UID (block_head),
346 next_insn != block_head,
347 (e->flags & EDGE_ABNORMAL ? 2 : 0));
349 if (block_head == next_insn)
350 edge_printed = 1;
352 else
354 draw_edge (fp, INSN_UID (tmp_rtx), 999999,
355 next_insn != 0,
356 (e->flags & EDGE_ABNORMAL ? 2 : 0));
358 if (next_insn == 0)
359 edge_printed = 1;
364 if (!edge_printed)
366 /* Don't print edges to barriers. */
367 if (next_insn == 0
368 || GET_CODE (next_insn) != BARRIER)
369 draw_edge (fp, XINT (tmp_rtx, 0),
370 next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
371 else
373 /* We draw the remaining edges in class 3. We have
374 to skip over the barrier since these nodes are
375 not printed at all. */
377 next_insn = NEXT_INSN (next_insn);
378 while (next_insn
379 && (GET_CODE (next_insn) == NOTE
380 || GET_CODE (next_insn) == BARRIER));
382 draw_edge (fp, XINT (tmp_rtx, 0),
383 next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
388 dump_for_graph = 0;
390 end_fct (fp);
392 /* Clean up. */
393 free (start);
394 free (end);
395 free (in_bb_p);
398 fclose (fp);
402 /* Similar as clean_dump_file, but this time for graph output files. */
404 void
405 clean_graph_dump_file (base, suffix)
406 const char *base;
407 const char *suffix;
409 size_t namelen = strlen (base);
410 size_t suffixlen = strlen (suffix);
411 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
412 char *buf = (char *) alloca (namelen + extlen + suffixlen);
413 FILE *fp;
415 memcpy (buf, base, namelen);
416 memcpy (buf + namelen, suffix, suffixlen);
417 memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
419 fp = fopen (buf, "w");
421 if (fp == NULL)
422 fatal_io_error ("can't open %s", buf);
424 switch (graph_dump_format)
426 case vcg:
427 fputs ("graph: {\nport_sharing: no\n", fp);
428 break;
429 case no_graph:
430 abort ();
433 fclose (fp);
437 /* Do final work on the graph output file. */
438 void
439 finish_graph_dump_file (base, suffix)
440 const char *base;
441 const char *suffix;
443 size_t namelen = strlen (base);
444 size_t suffixlen = strlen (suffix);
445 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
446 char *buf = (char *) alloca (namelen + suffixlen + extlen);
447 FILE *fp;
449 memcpy (buf, base, namelen);
450 memcpy (buf + namelen, suffix, suffixlen);
451 memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
453 fp = fopen (buf, "a");
454 if (fp != NULL)
456 switch (graph_dump_format)
458 case vcg:
459 fputs ("}\n", fp);
460 break;
461 case no_graph:
462 abort ();
465 fclose (fp);