]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/graph.c
Merge basic-improvements-branch to trunk
[thirdparty/gcc.git] / gcc / graph.c
CommitLineData
3eaf50a4 1/* Output routines for graphical representation.
f060a027 2 Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3eaf50a4 3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
4
f12b58b3 5This file is part of GCC.
3eaf50a4 6
f12b58b3 7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
3eaf50a4 11
f12b58b3 12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
3eaf50a4 16
f060a027 17You should have received a copy of the GNU General Public License
f12b58b3 18along with GCC; see the file COPYING. If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2002111-1307, USA. */
3eaf50a4 21
22#include <config.h>
23#include "system.h"
805e22b2 24#include "coretypes.h"
25#include "tm.h"
3eaf50a4 26
27#include "rtl.h"
28#include "flags.h"
29#include "output.h"
0a893c29 30#include "function.h"
3eaf50a4 31#include "hard-reg-set.h"
32#include "basic-block.h"
33#include "toplev.h"
e5bd1365 34#include "graph.h"
3eaf50a4 35
35823b64 36static const char *const graph_ext[] =
3eaf50a4 37{
38 /* no_graph */ "",
39 /* vcg */ ".vcg",
40};
41
38b9004f 42static void start_fct PARAMS ((FILE *));
43static void start_bb PARAMS ((FILE *, int));
44static void node_data PARAMS ((FILE *, rtx));
45static void draw_edge PARAMS ((FILE *, int, int, int, int));
46static void end_fct PARAMS ((FILE *));
47static void end_bb PARAMS ((FILE *));
fdeac5ce 48
3eaf50a4 49/* Output text for new basic block. */
50static void
51start_fct (fp)
52 FILE *fp;
53{
54
55 switch (graph_dump_format)
56 {
57 case vcg:
58 fprintf (fp, "\
59graph: { 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;
64 }
65}
66
67static void
68start_bb (fp, bb)
69 FILE *fp;
70 int bb;
71{
72 switch (graph_dump_format)
73 {
74 case vcg:
75 fprintf (fp, "\
76graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\
77label: \"basic block %d",
78 current_function_name, bb, bb);
79 break;
80 case no_graph:
81 break;
82 }
83
84#if 0
aa40f561 85 /* FIXME Should this be printed? It makes the graph significantly larger. */
3eaf50a4 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,
90 {
91 fprintf (fp, " %d", i);
92 if (i < FIRST_PSEUDO_REGISTER)
93 fprintf (fp, " [%s]",
94 reg_names[i]);
95 });
96#endif
97
98 switch (graph_dump_format)
99 {
100 case vcg:
101 fputs ("\"\n\n", fp);
102 break;
103 case no_graph:
104 break;
105 }
106}
107
7bbc47e8 108static void
3eaf50a4 109node_data (fp, tmp_rtx)
110 FILE *fp;
111 rtx tmp_rtx;
112{
3eaf50a4 113
114 if (PREV_INSN (tmp_rtx) == 0)
115 {
116 /* This is the first instruction. Add an edge from the starting
117 block. */
118 switch (graph_dump_format)
119 {
120 case vcg:
121 fprintf (fp, "\
122edge: { 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;
128 }
129 }
130
131 switch (graph_dump_format)
132 {
133 case vcg:
134 fprintf (fp, "node: {\n title: \"%s.%d\"\n color: %s\n \
135label: \"%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 ? "\
142darkgrey\n shape: ellipse" : "white",
143 GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0));
144 break;
145 case no_graph:
146 break;
147 }
148
149 /* Print the RTL. */
150 if (GET_CODE (tmp_rtx) == NOTE)
151 {
eb1c92fb 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);
3eaf50a4 156 }
9204e736 157 else if (INSN_P (tmp_rtx))
7bbc47e8 158 print_rtl_single (fp, PATTERN (tmp_rtx));
3eaf50a4 159 else
7bbc47e8 160 print_rtl_single (fp, tmp_rtx);
3eaf50a4 161
162 switch (graph_dump_format)
163 {
164 case vcg:
165 fputs ("\"\n}\n", fp);
166 break;
167 case no_graph:
168 break;
169 }
3eaf50a4 170}
171
172static void
173draw_edge (fp, from, to, bb_edge, class)
174 FILE *fp;
175 int from;
176 int to;
177 int bb_edge;
178 int class;
179{
fdeac5ce 180 const char * color;
3eaf50a4 181 switch (graph_dump_format)
182 {
183 case vcg:
71caadc0 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 ";
3eaf50a4 191 fprintf (fp,
192 "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
193 current_function_name, from,
71caadc0 194 current_function_name, to, color);
3eaf50a4 195 if (class)
196 fprintf (fp, "class: %d ", class);
197 fputs ("}\n", fp);
198 break;
199 case no_graph:
200 break;
201 }
202}
203
204static void
fdeac5ce 205end_bb (fp)
3eaf50a4 206 FILE *fp;
3eaf50a4 207{
208 switch (graph_dump_format)
209 {
210 case vcg:
211 fputs ("}\n", fp);
212 break;
213 case no_graph:
214 break;
215 }
216}
217
218static void
219end_fct (fp)
220 FILE *fp;
221{
222 switch (graph_dump_format)
223 {
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;
230 }
231}
232\f
233/* Like print_rtl, but also print out live information for the start of each
234 basic block. */
235void
236print_rtl_graph_with_bb (base, suffix, rtx_first)
237 const char *base;
238 const char *suffix;
239 rtx rtx_first;
240{
19cb6b50 241 rtx tmp_rtx;
3eaf50a4 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;
247
71caadc0 248 if (basic_block_info == NULL)
249 return;
3eaf50a4 250
251 memcpy (buf, base, namelen);
252 memcpy (buf + namelen, suffix, suffixlen);
253 memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
254
255 fp = fopen (buf, "a");
256 if (fp == NULL)
257 return;
258
259 if (rtx_first == 0)
260 fprintf (fp, "(nil)\n");
261 else
262 {
3eaf50a4 263 enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
264 int max_uid = get_max_uid ();
b9cf3f63 265 int *start = (int *) xmalloc (max_uid * sizeof (int));
266 int *end = (int *) xmalloc (max_uid * sizeof (int));
3eaf50a4 267 enum bb_state *in_bb_p = (enum bb_state *)
b9cf3f63 268 xmalloc (max_uid * sizeof (enum bb_state));
71caadc0 269 basic_block bb;
4c26117a 270 int i;
3eaf50a4 271
b3d6de89 272 for (i = 0; i < max_uid; ++i)
3eaf50a4 273 {
b3d6de89 274 start[i] = end[i] = -1;
275 in_bb_p[i] = NOT_IN_BB;
3eaf50a4 276 }
277
4c26117a 278 FOR_EACH_BB_REVERSE (bb)
3eaf50a4 279 {
280 rtx x;
4c26117a 281 start[INSN_UID (bb->head)] = bb->index;
282 end[INSN_UID (bb->end)] = bb->index;
71caadc0 283 for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x))
3eaf50a4 284 {
285 in_bb_p[INSN_UID (x)]
286 = (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
287 ? IN_ONE_BB : IN_MULTIPLE_BB;
71caadc0 288 if (x == bb->end)
3eaf50a4 289 break;
290 }
291 }
292
3eaf50a4 293 /* Tell print-rtl that we want graph output. */
294 dump_for_graph = 1;
295
296 /* Start new function. */
297 start_fct (fp);
298
299 for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx;
300 tmp_rtx = NEXT_INSN (tmp_rtx))
301 {
3eaf50a4 302 int edge_printed = 0;
303 rtx next_insn;
304
305 if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
306 {
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;
312 }
313
b3d6de89 314 if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
3eaf50a4 315 {
316 /* We start a subgraph for each basic block. */
b3d6de89 317 start_bb (fp, i);
3eaf50a4 318
b3d6de89 319 if (i == 0)
3eaf50a4 320 draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
321 }
322
323 /* Print the data for this node. */
7bbc47e8 324 node_data (fp, tmp_rtx);
3eaf50a4 325 next_insn = next_nonnote_insn (tmp_rtx);
326
b3d6de89 327 if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
3eaf50a4 328 {
71caadc0 329 edge e;
330
b3d6de89 331 bb = BASIC_BLOCK (i);
3eaf50a4 332
333 /* End of the basic block. */
fdeac5ce 334 end_bb (fp);
3eaf50a4 335
336 /* Now specify the edges to all the successors of this
337 basic block. */
71caadc0 338 for (e = bb->succ; e ; e = e->succ_next)
3eaf50a4 339 {
71caadc0 340 if (e->dest != EXIT_BLOCK_PTR)
3eaf50a4 341 {
71caadc0 342 rtx block_head = e->dest->head;
3eaf50a4 343
344 draw_edge (fp, INSN_UID (tmp_rtx),
345 INSN_UID (block_head),
71caadc0 346 next_insn != block_head,
347 (e->flags & EDGE_ABNORMAL ? 2 : 0));
3eaf50a4 348
71caadc0 349 if (block_head == next_insn)
3eaf50a4 350 edge_printed = 1;
351 }
71caadc0 352 else
3eaf50a4 353 {
354 draw_edge (fp, INSN_UID (tmp_rtx), 999999,
71caadc0 355 next_insn != 0,
356 (e->flags & EDGE_ABNORMAL ? 2 : 0));
3eaf50a4 357
358 if (next_insn == 0)
359 edge_printed = 1;
360 }
3eaf50a4 361 }
362 }
363
364 if (!edge_printed)
365 {
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
372 {
71caadc0 373 /* We draw the remaining edges in class 3. We have
374 to skip over the barrier since these nodes are
3eaf50a4 375 not printed at all. */
376 do
377 next_insn = NEXT_INSN (next_insn);
378 while (next_insn
379 && (GET_CODE (next_insn) == NOTE
380 || GET_CODE (next_insn) == BARRIER));
381
382 draw_edge (fp, XINT (tmp_rtx, 0),
71caadc0 383 next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
3eaf50a4 384 }
385 }
386 }
387
388 dump_for_graph = 0;
389
390 end_fct (fp);
b9cf3f63 391
392 /* Clean up. */
393 free (start);
394 free (end);
395 free (in_bb_p);
3eaf50a4 396 }
397
398 fclose (fp);
399}
400
401
402/* Similar as clean_dump_file, but this time for graph output files. */
f060a027 403
3eaf50a4 404void
405clean_graph_dump_file (base, suffix)
406 const char *base;
407 const char *suffix;
408{
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;
414
415 memcpy (buf, base, namelen);
416 memcpy (buf + namelen, suffix, suffixlen);
417 memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
418
419 fp = fopen (buf, "w");
420
421 if (fp == NULL)
f060a027 422 fatal_io_error ("can't open %s", buf);
3eaf50a4 423
424 switch (graph_dump_format)
425 {
426 case vcg:
427 fputs ("graph: {\nport_sharing: no\n", fp);
428 break;
429 case no_graph:
430 abort ();
431 }
432
433 fclose (fp);
434}
435
436
437/* Do final work on the graph output file. */
438void
439finish_graph_dump_file (base, suffix)
440 const char *base;
441 const char *suffix;
442{
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;
448
449 memcpy (buf, base, namelen);
450 memcpy (buf + namelen, suffix, suffixlen);
451 memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
452
453 fp = fopen (buf, "a");
454 if (fp != NULL)
455 {
456 switch (graph_dump_format)
457 {
458 case vcg:
459 fputs ("}\n", fp);
460 break;
461 case no_graph:
462 abort ();
463 }
464
465 fclose (fp);
466 }
467}