graph.c revision 90075
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. 4 5This file is part of GCC. 6 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. 11 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. 16 17You should have received a copy of the GNU General Public License 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. */ 21 22#include <config.h> 23#include "system.h" 24 25#include "rtl.h" 26#include "flags.h" 27#include "output.h" 28#include "function.h" 29#include "hard-reg-set.h" 30#include "basic-block.h" 31#include "toplev.h" 32#include "graph.h" 33 34static const char *const graph_ext[] = 35{ 36 /* no_graph */ "", 37 /* vcg */ ".vcg", 38}; 39 40static void start_fct PARAMS ((FILE *)); 41static void start_bb PARAMS ((FILE *, int)); 42static void node_data PARAMS ((FILE *, rtx)); 43static void draw_edge PARAMS ((FILE *, int, int, int, int)); 44static void end_fct PARAMS ((FILE *)); 45static void end_bb PARAMS ((FILE *)); 46 47/* Output text for new basic block. */ 48static void 49start_fct (fp) 50 FILE *fp; 51{ 52 53 switch (graph_dump_format) 54 { 55 case vcg: 56 fprintf (fp, "\ 57graph: { 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 65static void 66start_bb (fp, bb) 67 FILE *fp; 68 int bb; 69{ 70 switch (graph_dump_format) 71 { 72 case vcg: 73 fprintf (fp, "\ 74graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\ 75label: \"basic block %d", 76 current_function_name, bb, bb); 77 break; 78 case no_graph: 79 break; 80 } 81 82#if 0 83 /* FIXME Should this be printed? It makes the graph significantly larger. */ 84 85 /* Print the live-at-start register list. */ 86 fputc ('\n', fp); 87 EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i, 88 { 89 fprintf (fp, " %d", i); 90 if (i < FIRST_PSEUDO_REGISTER) 91 fprintf (fp, " [%s]", 92 reg_names[i]); 93 }); 94#endif 95 96 switch (graph_dump_format) 97 { 98 case vcg: 99 fputs ("\"\n\n", fp); 100 break; 101 case no_graph: 102 break; 103 } 104} 105 106static void 107node_data (fp, tmp_rtx) 108 FILE *fp; 109 rtx tmp_rtx; 110{ 111 112 if (PREV_INSN (tmp_rtx) == 0) 113 { 114 /* This is the first instruction. Add an edge from the starting 115 block. */ 116 switch (graph_dump_format) 117 { 118 case vcg: 119 fprintf (fp, "\ 120edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n", 121 current_function_name, 122 current_function_name, XINT (tmp_rtx, 0)); 123 break; 124 case no_graph: 125 break; 126 } 127 } 128 129 switch (graph_dump_format) 130 { 131 case vcg: 132 fprintf (fp, "node: {\n title: \"%s.%d\"\n color: %s\n \ 133label: \"%s %d\n", 134 current_function_name, XINT (tmp_rtx, 0), 135 GET_CODE (tmp_rtx) == NOTE ? "lightgrey" 136 : GET_CODE (tmp_rtx) == INSN ? "green" 137 : GET_CODE (tmp_rtx) == JUMP_INSN ? "darkgreen" 138 : GET_CODE (tmp_rtx) == CALL_INSN ? "darkgreen" 139 : GET_CODE (tmp_rtx) == CODE_LABEL ? "\ 140darkgrey\n shape: ellipse" : "white", 141 GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0)); 142 break; 143 case no_graph: 144 break; 145 } 146 147 /* Print the RTL. */ 148 if (GET_CODE (tmp_rtx) == NOTE) 149 { 150 const char *name = ""; 151 if (NOTE_LINE_NUMBER (tmp_rtx) < 0) 152 name = GET_NOTE_INSN_NAME (NOTE_LINE_NUMBER (tmp_rtx)); 153 fprintf (fp, " %s", name); 154 } 155 else if (INSN_P (tmp_rtx)) 156 print_rtl_single (fp, PATTERN (tmp_rtx)); 157 else 158 print_rtl_single (fp, tmp_rtx); 159 160 switch (graph_dump_format) 161 { 162 case vcg: 163 fputs ("\"\n}\n", fp); 164 break; 165 case no_graph: 166 break; 167 } 168} 169 170static void 171draw_edge (fp, from, to, bb_edge, class) 172 FILE *fp; 173 int from; 174 int to; 175 int bb_edge; 176 int class; 177{ 178 const char * color; 179 switch (graph_dump_format) 180 { 181 case vcg: 182 color = ""; 183 if (class == 2) 184 color = "color: red "; 185 else if (bb_edge) 186 color = "color: blue "; 187 else if (class == 3) 188 color = "color: green "; 189 fprintf (fp, 190 "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s", 191 current_function_name, from, 192 current_function_name, to, color); 193 if (class) 194 fprintf (fp, "class: %d ", class); 195 fputs ("}\n", fp); 196 break; 197 case no_graph: 198 break; 199 } 200} 201 202static void 203end_bb (fp) 204 FILE *fp; 205{ 206 switch (graph_dump_format) 207 { 208 case vcg: 209 fputs ("}\n", fp); 210 break; 211 case no_graph: 212 break; 213 } 214} 215 216static void 217end_fct (fp) 218 FILE *fp; 219{ 220 switch (graph_dump_format) 221 { 222 case vcg: 223 fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n", 224 current_function_name); 225 break; 226 case no_graph: 227 break; 228 } 229} 230 231/* Like print_rtl, but also print out live information for the start of each 232 basic block. */ 233void 234print_rtl_graph_with_bb (base, suffix, rtx_first) 235 const char *base; 236 const char *suffix; 237 rtx rtx_first; 238{ 239 rtx tmp_rtx; 240 size_t namelen = strlen (base); 241 size_t suffixlen = strlen (suffix); 242 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; 243 char *buf = (char *) alloca (namelen + suffixlen + extlen); 244 FILE *fp; 245 246 if (basic_block_info == NULL) 247 return; 248 249 memcpy (buf, base, namelen); 250 memcpy (buf + namelen, suffix, suffixlen); 251 memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen); 252 253 fp = fopen (buf, "a"); 254 if (fp == NULL) 255 return; 256 257 if (rtx_first == 0) 258 fprintf (fp, "(nil)\n"); 259 else 260 { 261 int i; 262 enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB }; 263 int max_uid = get_max_uid (); 264 int *start = (int *) xmalloc (max_uid * sizeof (int)); 265 int *end = (int *) xmalloc (max_uid * sizeof (int)); 266 enum bb_state *in_bb_p = (enum bb_state *) 267 xmalloc (max_uid * sizeof (enum bb_state)); 268 basic_block bb; 269 270 for (i = 0; i < max_uid; ++i) 271 { 272 start[i] = end[i] = -1; 273 in_bb_p[i] = NOT_IN_BB; 274 } 275 276 for (i = n_basic_blocks - 1; i >= 0; --i) 277 { 278 rtx x; 279 bb = BASIC_BLOCK (i); 280 start[INSN_UID (bb->head)] = i; 281 end[INSN_UID (bb->end)] = i; 282 for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x)) 283 { 284 in_bb_p[INSN_UID (x)] 285 = (in_bb_p[INSN_UID (x)] == NOT_IN_BB) 286 ? IN_ONE_BB : IN_MULTIPLE_BB; 287 if (x == bb->end) 288 break; 289 } 290 } 291 292 /* Tell print-rtl that we want graph output. */ 293 dump_for_graph = 1; 294 295 /* Start new function. */ 296 start_fct (fp); 297 298 for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx; 299 tmp_rtx = NEXT_INSN (tmp_rtx)) 300 { 301 int edge_printed = 0; 302 rtx next_insn; 303 304 if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0) 305 { 306 if (GET_CODE (tmp_rtx) == BARRIER) 307 continue; 308 if (GET_CODE (tmp_rtx) == NOTE 309 && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB)) 310 continue; 311 } 312 313 if ((i = start[INSN_UID (tmp_rtx)]) >= 0) 314 { 315 /* We start a subgraph for each basic block. */ 316 start_bb (fp, i); 317 318 if (i == 0) 319 draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0); 320 } 321 322 /* Print the data for this node. */ 323 node_data (fp, tmp_rtx); 324 next_insn = next_nonnote_insn (tmp_rtx); 325 326 if ((i = end[INSN_UID (tmp_rtx)]) >= 0) 327 { 328 edge e; 329 330 bb = BASIC_BLOCK (i); 331 332 /* End of the basic block. */ 333 end_bb (fp); 334 335 /* Now specify the edges to all the successors of this 336 basic block. */ 337 for (e = bb->succ; e ; e = e->succ_next) 338 { 339 if (e->dest != EXIT_BLOCK_PTR) 340 { 341 rtx block_head = e->dest->head; 342 343 draw_edge (fp, INSN_UID (tmp_rtx), 344 INSN_UID (block_head), 345 next_insn != block_head, 346 (e->flags & EDGE_ABNORMAL ? 2 : 0)); 347 348 if (block_head == next_insn) 349 edge_printed = 1; 350 } 351 else 352 { 353 draw_edge (fp, INSN_UID (tmp_rtx), 999999, 354 next_insn != 0, 355 (e->flags & EDGE_ABNORMAL ? 2 : 0)); 356 357 if (next_insn == 0) 358 edge_printed = 1; 359 } 360 } 361 } 362 363 if (!edge_printed) 364 { 365 /* Don't print edges to barriers. */ 366 if (next_insn == 0 367 || GET_CODE (next_insn) != BARRIER) 368 draw_edge (fp, XINT (tmp_rtx, 0), 369 next_insn ? INSN_UID (next_insn) : 999999, 0, 0); 370 else 371 { 372 /* We draw the remaining edges in class 3. We have 373 to skip over the barrier since these nodes are 374 not printed at all. */ 375 do 376 next_insn = NEXT_INSN (next_insn); 377 while (next_insn 378 && (GET_CODE (next_insn) == NOTE 379 || GET_CODE (next_insn) == BARRIER)); 380 381 draw_edge (fp, XINT (tmp_rtx, 0), 382 next_insn ? INSN_UID (next_insn) : 999999, 0, 3); 383 } 384 } 385 } 386 387 dump_for_graph = 0; 388 389 end_fct (fp); 390 391 /* Clean up. */ 392 free (start); 393 free (end); 394 free (in_bb_p); 395 } 396 397 fclose (fp); 398} 399 400 401/* Similar as clean_dump_file, but this time for graph output files. */ 402 403void 404clean_graph_dump_file (base, suffix) 405 const char *base; 406 const char *suffix; 407{ 408 size_t namelen = strlen (base); 409 size_t suffixlen = strlen (suffix); 410 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; 411 char *buf = (char *) alloca (namelen + extlen + suffixlen); 412 FILE *fp; 413 414 memcpy (buf, base, namelen); 415 memcpy (buf + namelen, suffix, suffixlen); 416 memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen); 417 418 fp = fopen (buf, "w"); 419 420 if (fp == NULL) 421 fatal_io_error ("can't open %s", buf); 422 423 switch (graph_dump_format) 424 { 425 case vcg: 426 fputs ("graph: {\nport_sharing: no\n", fp); 427 break; 428 case no_graph: 429 abort (); 430 } 431 432 fclose (fp); 433} 434 435 436/* Do final work on the graph output file. */ 437void 438finish_graph_dump_file (base, suffix) 439 const char *base; 440 const char *suffix; 441{ 442 size_t namelen = strlen (base); 443 size_t suffixlen = strlen (suffix); 444 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; 445 char *buf = (char *) alloca (namelen + suffixlen + extlen); 446 FILE *fp; 447 448 memcpy (buf, base, namelen); 449 memcpy (buf + namelen, suffix, suffixlen); 450 memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen); 451 452 fp = fopen (buf, "a"); 453 if (fp != NULL) 454 { 455 switch (graph_dump_format) 456 { 457 case vcg: 458 fputs ("}\n", fp); 459 break; 460 case no_graph: 461 abort (); 462 } 463 464 fclose (fp); 465 } 466} 467