152284Sobrien/* Output routines for graphical representation. 2132718Skan Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004 3132718Skan Free Software Foundation, Inc. 452284Sobrien Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. 552284Sobrien 690075SobrienThis file is part of GCC. 752284Sobrien 890075SobrienGCC is free software; you can redistribute it and/or modify it under 990075Sobrienthe terms of the GNU General Public License as published by the Free 1090075SobrienSoftware Foundation; either version 2, or (at your option) any later 1190075Sobrienversion. 1252284Sobrien 1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1590075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1690075Sobrienfor more details. 1752284Sobrien 1890075SobrienYou should have received a copy of the GNU General Public License 1990075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 20169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 21169689Skan02110-1301, USA. */ 2252284Sobrien 2352284Sobrien#include <config.h> 2452284Sobrien#include "system.h" 25132718Skan#include "coretypes.h" 26132718Skan#include "tm.h" 2752284Sobrien#include "rtl.h" 2852284Sobrien#include "flags.h" 2952284Sobrien#include "output.h" 3090075Sobrien#include "function.h" 3152284Sobrien#include "hard-reg-set.h" 32169689Skan#include "obstack.h" 3352284Sobrien#include "basic-block.h" 3452284Sobrien#include "toplev.h" 3590075Sobrien#include "graph.h" 3652284Sobrien 3790075Sobrienstatic const char *const graph_ext[] = 3852284Sobrien{ 3952284Sobrien /* no_graph */ "", 4052284Sobrien /* vcg */ ".vcg", 4152284Sobrien}; 4252284Sobrien 43132718Skanstatic void start_fct (FILE *); 44132718Skanstatic void start_bb (FILE *, int); 45132718Skanstatic void node_data (FILE *, rtx); 46132718Skanstatic void draw_edge (FILE *, int, int, int, int); 47132718Skanstatic void end_fct (FILE *); 48132718Skanstatic void end_bb (FILE *); 4990075Sobrien 5052284Sobrien/* Output text for new basic block. */ 5152284Sobrienstatic void 52132718Skanstart_fct (FILE *fp) 5352284Sobrien{ 5452284Sobrien switch (graph_dump_format) 5552284Sobrien { 5652284Sobrien case vcg: 5752284Sobrien fprintf (fp, "\ 5852284Sobriengraph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n", 59132718Skan current_function_name (), current_function_name ()); 6052284Sobrien break; 6152284Sobrien case no_graph: 6252284Sobrien break; 6352284Sobrien } 6452284Sobrien} 6552284Sobrien 6652284Sobrienstatic void 67132718Skanstart_bb (FILE *fp, int bb) 6852284Sobrien{ 69169689Skan#if 0 70169689Skan reg_set_iterator rsi; 71169689Skan#endif 72169689Skan 7352284Sobrien switch (graph_dump_format) 7452284Sobrien { 7552284Sobrien case vcg: 7652284Sobrien fprintf (fp, "\ 7752284Sobriengraph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\ 7852284Sobrienlabel: \"basic block %d", 79132718Skan current_function_name (), bb, bb); 8052284Sobrien break; 8152284Sobrien case no_graph: 8252284Sobrien break; 8352284Sobrien } 8452284Sobrien 8552284Sobrien#if 0 8690075Sobrien /* FIXME Should this be printed? It makes the graph significantly larger. */ 8752284Sobrien 8852284Sobrien /* Print the live-at-start register list. */ 8952284Sobrien fputc ('\n', fp); 90169689Skan EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i, rsi) 91169689Skan { 92169689Skan fprintf (fp, " %d", i); 93169689Skan if (i < FIRST_PSEUDO_REGISTER) 94169689Skan fprintf (fp, " [%s]", reg_names[i]); 95169689Skan } 9652284Sobrien#endif 9752284Sobrien 9852284Sobrien switch (graph_dump_format) 9952284Sobrien { 10052284Sobrien case vcg: 10152284Sobrien fputs ("\"\n\n", fp); 10252284Sobrien break; 10352284Sobrien case no_graph: 10452284Sobrien break; 10552284Sobrien } 10652284Sobrien} 10752284Sobrien 10852284Sobrienstatic void 109132718Skannode_data (FILE *fp, rtx tmp_rtx) 11052284Sobrien{ 11152284Sobrien if (PREV_INSN (tmp_rtx) == 0) 11252284Sobrien { 11352284Sobrien /* This is the first instruction. Add an edge from the starting 11452284Sobrien block. */ 11552284Sobrien switch (graph_dump_format) 11652284Sobrien { 11752284Sobrien case vcg: 11852284Sobrien fprintf (fp, "\ 11952284Sobrienedge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n", 120132718Skan current_function_name (), 121132718Skan current_function_name (), XINT (tmp_rtx, 0)); 12252284Sobrien break; 12352284Sobrien case no_graph: 12452284Sobrien break; 12552284Sobrien } 12652284Sobrien } 12752284Sobrien 12852284Sobrien switch (graph_dump_format) 12952284Sobrien { 13052284Sobrien case vcg: 13152284Sobrien fprintf (fp, "node: {\n title: \"%s.%d\"\n color: %s\n \ 13252284Sobrienlabel: \"%s %d\n", 133132718Skan current_function_name (), XINT (tmp_rtx, 0), 134169689Skan NOTE_P (tmp_rtx) ? "lightgrey" 135169689Skan : NONJUMP_INSN_P (tmp_rtx) ? "green" 136169689Skan : JUMP_P (tmp_rtx) ? "darkgreen" 137169689Skan : CALL_P (tmp_rtx) ? "darkgreen" 138169689Skan : LABEL_P (tmp_rtx) ? "\ 13952284Sobriendarkgrey\n shape: ellipse" : "white", 14052284Sobrien GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0)); 14152284Sobrien break; 14252284Sobrien case no_graph: 14352284Sobrien break; 14452284Sobrien } 14552284Sobrien 14652284Sobrien /* Print the RTL. */ 147169689Skan if (NOTE_P (tmp_rtx)) 14852284Sobrien { 14990075Sobrien const char *name = ""; 15090075Sobrien if (NOTE_LINE_NUMBER (tmp_rtx) < 0) 15190075Sobrien name = GET_NOTE_INSN_NAME (NOTE_LINE_NUMBER (tmp_rtx)); 15290075Sobrien fprintf (fp, " %s", name); 15352284Sobrien } 15490075Sobrien else if (INSN_P (tmp_rtx)) 15552284Sobrien print_rtl_single (fp, PATTERN (tmp_rtx)); 15652284Sobrien else 15752284Sobrien print_rtl_single (fp, tmp_rtx); 15852284Sobrien 15952284Sobrien switch (graph_dump_format) 16052284Sobrien { 16152284Sobrien case vcg: 16252284Sobrien fputs ("\"\n}\n", fp); 16352284Sobrien break; 16452284Sobrien case no_graph: 16552284Sobrien break; 16652284Sobrien } 16752284Sobrien} 16852284Sobrien 16952284Sobrienstatic void 170132718Skandraw_edge (FILE *fp, int from, int to, int bb_edge, int class) 17152284Sobrien{ 17290075Sobrien const char * color; 17352284Sobrien switch (graph_dump_format) 17452284Sobrien { 17552284Sobrien case vcg: 17652284Sobrien color = ""; 17752284Sobrien if (class == 2) 17852284Sobrien color = "color: red "; 17952284Sobrien else if (bb_edge) 18052284Sobrien color = "color: blue "; 18152284Sobrien else if (class == 3) 18252284Sobrien color = "color: green "; 18352284Sobrien fprintf (fp, 18452284Sobrien "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s", 185132718Skan current_function_name (), from, 186132718Skan current_function_name (), to, color); 18752284Sobrien if (class) 18852284Sobrien fprintf (fp, "class: %d ", class); 18952284Sobrien fputs ("}\n", fp); 19052284Sobrien break; 19152284Sobrien case no_graph: 19252284Sobrien break; 19352284Sobrien } 19452284Sobrien} 19552284Sobrien 19652284Sobrienstatic void 197132718Skanend_bb (FILE *fp) 19852284Sobrien{ 19952284Sobrien switch (graph_dump_format) 20052284Sobrien { 20152284Sobrien case vcg: 20252284Sobrien fputs ("}\n", fp); 20352284Sobrien break; 20452284Sobrien case no_graph: 20552284Sobrien break; 20652284Sobrien } 20752284Sobrien} 20852284Sobrien 20952284Sobrienstatic void 210132718Skanend_fct (FILE *fp) 21152284Sobrien{ 21252284Sobrien switch (graph_dump_format) 21352284Sobrien { 21452284Sobrien case vcg: 21552284Sobrien fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n", 216132718Skan current_function_name ()); 21752284Sobrien break; 21852284Sobrien case no_graph: 21952284Sobrien break; 22052284Sobrien } 22152284Sobrien} 22252284Sobrien 22352284Sobrien/* Like print_rtl, but also print out live information for the start of each 22452284Sobrien basic block. */ 22552284Sobrienvoid 226169689Skanprint_rtl_graph_with_bb (const char *base, rtx rtx_first) 22752284Sobrien{ 22890075Sobrien rtx tmp_rtx; 22952284Sobrien size_t namelen = strlen (base); 23052284Sobrien size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; 231169689Skan char *buf = alloca (namelen + extlen); 23252284Sobrien FILE *fp; 23352284Sobrien 23452284Sobrien if (basic_block_info == NULL) 23552284Sobrien return; 23652284Sobrien 23752284Sobrien memcpy (buf, base, namelen); 238169689Skan memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); 23952284Sobrien 24052284Sobrien fp = fopen (buf, "a"); 24152284Sobrien if (fp == NULL) 24252284Sobrien return; 24352284Sobrien 24452284Sobrien if (rtx_first == 0) 24552284Sobrien fprintf (fp, "(nil)\n"); 24652284Sobrien else 24752284Sobrien { 24852284Sobrien enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB }; 24952284Sobrien int max_uid = get_max_uid (); 250169689Skan int *start = XNEWVEC (int, max_uid); 251169689Skan int *end = XNEWVEC (int, max_uid); 252169689Skan enum bb_state *in_bb_p = XNEWVEC (enum bb_state, max_uid); 25352284Sobrien basic_block bb; 254117395Skan int i; 25552284Sobrien 25652284Sobrien for (i = 0; i < max_uid; ++i) 25752284Sobrien { 25852284Sobrien start[i] = end[i] = -1; 25952284Sobrien in_bb_p[i] = NOT_IN_BB; 26052284Sobrien } 26152284Sobrien 262117395Skan FOR_EACH_BB_REVERSE (bb) 26352284Sobrien { 26452284Sobrien rtx x; 265132718Skan start[INSN_UID (BB_HEAD (bb))] = bb->index; 266132718Skan end[INSN_UID (BB_END (bb))] = bb->index; 267132718Skan for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x)) 26852284Sobrien { 26952284Sobrien in_bb_p[INSN_UID (x)] 27052284Sobrien = (in_bb_p[INSN_UID (x)] == NOT_IN_BB) 27152284Sobrien ? IN_ONE_BB : IN_MULTIPLE_BB; 272132718Skan if (x == BB_END (bb)) 27352284Sobrien break; 27452284Sobrien } 27552284Sobrien } 27652284Sobrien 27752284Sobrien /* Tell print-rtl that we want graph output. */ 27852284Sobrien dump_for_graph = 1; 27952284Sobrien 28052284Sobrien /* Start new function. */ 28152284Sobrien start_fct (fp); 28252284Sobrien 28352284Sobrien for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx; 28452284Sobrien tmp_rtx = NEXT_INSN (tmp_rtx)) 28552284Sobrien { 28652284Sobrien int edge_printed = 0; 28752284Sobrien rtx next_insn; 28852284Sobrien 28952284Sobrien if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0) 29052284Sobrien { 291169689Skan if (BARRIER_P (tmp_rtx)) 29252284Sobrien continue; 293169689Skan if (NOTE_P (tmp_rtx) 29452284Sobrien && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB)) 29552284Sobrien continue; 29652284Sobrien } 29752284Sobrien 29852284Sobrien if ((i = start[INSN_UID (tmp_rtx)]) >= 0) 29952284Sobrien { 30052284Sobrien /* We start a subgraph for each basic block. */ 30152284Sobrien start_bb (fp, i); 30252284Sobrien 30352284Sobrien if (i == 0) 30452284Sobrien draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0); 30552284Sobrien } 30652284Sobrien 30752284Sobrien /* Print the data for this node. */ 30852284Sobrien node_data (fp, tmp_rtx); 30952284Sobrien next_insn = next_nonnote_insn (tmp_rtx); 31052284Sobrien 31152284Sobrien if ((i = end[INSN_UID (tmp_rtx)]) >= 0) 31252284Sobrien { 31352284Sobrien edge e; 314169689Skan edge_iterator ei; 31552284Sobrien 31652284Sobrien bb = BASIC_BLOCK (i); 31752284Sobrien 31852284Sobrien /* End of the basic block. */ 31990075Sobrien end_bb (fp); 32052284Sobrien 32152284Sobrien /* Now specify the edges to all the successors of this 32252284Sobrien basic block. */ 323169689Skan FOR_EACH_EDGE (e, ei, bb->succs) 32452284Sobrien { 32552284Sobrien if (e->dest != EXIT_BLOCK_PTR) 32652284Sobrien { 327132718Skan rtx block_head = BB_HEAD (e->dest); 32852284Sobrien 32952284Sobrien draw_edge (fp, INSN_UID (tmp_rtx), 33052284Sobrien INSN_UID (block_head), 33152284Sobrien next_insn != block_head, 33252284Sobrien (e->flags & EDGE_ABNORMAL ? 2 : 0)); 33352284Sobrien 33452284Sobrien if (block_head == next_insn) 33552284Sobrien edge_printed = 1; 33652284Sobrien } 33752284Sobrien else 33852284Sobrien { 33952284Sobrien draw_edge (fp, INSN_UID (tmp_rtx), 999999, 34052284Sobrien next_insn != 0, 34152284Sobrien (e->flags & EDGE_ABNORMAL ? 2 : 0)); 34252284Sobrien 34352284Sobrien if (next_insn == 0) 34452284Sobrien edge_printed = 1; 34552284Sobrien } 34652284Sobrien } 34752284Sobrien } 34852284Sobrien 34952284Sobrien if (!edge_printed) 35052284Sobrien { 35152284Sobrien /* Don't print edges to barriers. */ 35252284Sobrien if (next_insn == 0 353169689Skan || !BARRIER_P (next_insn)) 35452284Sobrien draw_edge (fp, XINT (tmp_rtx, 0), 35552284Sobrien next_insn ? INSN_UID (next_insn) : 999999, 0, 0); 35652284Sobrien else 35752284Sobrien { 35852284Sobrien /* We draw the remaining edges in class 3. We have 35952284Sobrien to skip over the barrier since these nodes are 36052284Sobrien not printed at all. */ 36152284Sobrien do 36252284Sobrien next_insn = NEXT_INSN (next_insn); 36352284Sobrien while (next_insn 364169689Skan && (NOTE_P (next_insn) 365169689Skan || BARRIER_P (next_insn))); 36652284Sobrien 36752284Sobrien draw_edge (fp, XINT (tmp_rtx, 0), 36852284Sobrien next_insn ? INSN_UID (next_insn) : 999999, 0, 3); 36952284Sobrien } 37052284Sobrien } 37152284Sobrien } 37252284Sobrien 37352284Sobrien dump_for_graph = 0; 37452284Sobrien 37552284Sobrien end_fct (fp); 37690075Sobrien 37790075Sobrien /* Clean up. */ 37890075Sobrien free (start); 37990075Sobrien free (end); 38090075Sobrien free (in_bb_p); 38152284Sobrien } 38252284Sobrien 38352284Sobrien fclose (fp); 38452284Sobrien} 38552284Sobrien 38652284Sobrien 38752284Sobrien/* Similar as clean_dump_file, but this time for graph output files. */ 38890075Sobrien 38952284Sobrienvoid 390169689Skanclean_graph_dump_file (const char *base) 39152284Sobrien{ 39252284Sobrien size_t namelen = strlen (base); 39352284Sobrien size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; 394169689Skan char *buf = alloca (namelen + extlen); 39552284Sobrien FILE *fp; 39652284Sobrien 39752284Sobrien memcpy (buf, base, namelen); 398169689Skan memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); 39952284Sobrien 40052284Sobrien fp = fopen (buf, "w"); 40152284Sobrien 40252284Sobrien if (fp == NULL) 403132718Skan fatal_error ("can't open %s: %m", buf); 40452284Sobrien 405169689Skan gcc_assert (graph_dump_format == vcg); 406169689Skan fputs ("graph: {\nport_sharing: no\n", fp); 40752284Sobrien 40852284Sobrien fclose (fp); 40952284Sobrien} 41052284Sobrien 41152284Sobrien 41252284Sobrien/* Do final work on the graph output file. */ 41352284Sobrienvoid 414169689Skanfinish_graph_dump_file (const char *base) 41552284Sobrien{ 41652284Sobrien size_t namelen = strlen (base); 41752284Sobrien size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; 418169689Skan char *buf = alloca (namelen + extlen); 41952284Sobrien FILE *fp; 42052284Sobrien 42152284Sobrien memcpy (buf, base, namelen); 422169689Skan memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); 42352284Sobrien 42452284Sobrien fp = fopen (buf, "a"); 42552284Sobrien if (fp != NULL) 42652284Sobrien { 427169689Skan gcc_assert (graph_dump_format == vcg); 428169689Skan fputs ("}\n", fp); 42952284Sobrien fclose (fp); 43052284Sobrien } 43152284Sobrien} 432