1 /* Output routines for graphical representation. 2 Copyright (C) 1998-2013 Free Software Foundation, Inc. 3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. 4 Rewritten for DOT output by Steven Bosscher, 2012. 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 "diagnostic-core.h" /* for fatal_error */ 26 #include "sbitmap.h" 27 #include "basic-block.h" 28 #include "cfgloop.h" 29 #include "graph.h" 30 #include "dumpfile.h" 31 #include "pretty-print.h" 32 33 /* DOT files with the .dot extension are recognized as document templates 34 by a well-known piece of word processing software out of Redmond, WA. 35 Therefore some recommend using the .gv extension instead. Obstinately 36 ignore that recommendation... */ 37 static const char *const graph_ext = ".dot"; 38 39 /* Open a file with MODE for dumping our graph to. 40 Return the file pointer. */ 41 static FILE * 42 open_graph_file (const char *base, const char *mode) 43 { 44 size_t namelen = strlen (base); 45 size_t extlen = strlen (graph_ext) + 1; 46 char *buf = XALLOCAVEC (char, namelen + extlen); 47 FILE *fp; 48 49 memcpy (buf, base, namelen); 50 memcpy (buf + namelen, graph_ext, extlen); 51 52 fp = fopen (buf, mode); 53 if (fp == NULL) 54 fatal_error ("can%'t open %s: %m", buf); 55 56 return fp; 57 } 58 59 /* Return a pretty-print buffer for output to file FP. */ 60 61 static pretty_printer * 62 init_graph_slim_pretty_print (FILE *fp) 63 { 64 static bool initialized = false; 65 static pretty_printer graph_slim_pp; 66 67 if (! initialized) 68 { 69 pp_construct (&graph_slim_pp, /*prefix=*/NULL, /*linewidth=*/0); 70 initialized = true; 71 } 72 else 73 gcc_assert (! pp_last_position_in_text (&graph_slim_pp)); 74 75 graph_slim_pp.buffer->stream = fp; 76 return &graph_slim_pp; 77 } 78 79 /* Draw a basic block BB belonging to the function with FUNCDEF_NO 80 as its unique number. */ 81 static void 82 draw_cfg_node (pretty_printer *pp, int funcdef_no, basic_block bb) 83 { 84 const char *shape; 85 const char *fillcolor; 86 87 if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK) 88 { 89 shape = "Mdiamond"; 90 fillcolor = "white"; 91 } 92 else 93 { 94 shape = "record"; 95 fillcolor = 96 BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink" 97 : BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue" 98 : "lightgrey"; 99 } 100 101 pp_printf (pp, 102 "\tfn_%d_basic_block_%d " 103 "[shape=%s,style=filled,fillcolor=%s,label=\"", 104 funcdef_no, bb->index, shape, fillcolor); 105 106 if (bb->index == ENTRY_BLOCK) 107 pp_string (pp, "ENTRY"); 108 else if (bb->index == EXIT_BLOCK) 109 pp_string (pp, "EXIT"); 110 else 111 { 112 pp_character (pp, '{'); 113 pp_write_text_to_stream (pp); 114 dump_bb_for_graph (pp, bb); 115 pp_character (pp, '}'); 116 } 117 118 pp_string (pp, "\"];\n\n"); 119 pp_flush (pp); 120 } 121 122 /* Draw all successor edges of a basic block BB belonging to the function 123 with FUNCDEF_NO as its unique number. */ 124 static void 125 draw_cfg_node_succ_edges (pretty_printer *pp, int funcdef_no, basic_block bb) 126 { 127 edge e; 128 edge_iterator ei; 129 FOR_EACH_EDGE (e, ei, bb->succs) 130 { 131 const char *style = "\"solid,bold\""; 132 const char *color = "black"; 133 int weight = 10; 134 135 if (e->flags & EDGE_FAKE) 136 { 137 style = "dotted"; 138 color = "green"; 139 weight = 0; 140 } 141 else if (e->flags & EDGE_DFS_BACK) 142 { 143 style = "\"dotted,bold\""; 144 color = "blue"; 145 weight = 10; 146 } 147 else if (e->flags & EDGE_FALLTHRU) 148 { 149 color = "blue"; 150 weight = 100; 151 } 152 153 if (e->flags & EDGE_ABNORMAL) 154 color = "red"; 155 156 pp_printf (pp, 157 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n " 158 "[style=%s,color=%s,weight=%d,constraint=%s];\n", 159 funcdef_no, e->src->index, 160 funcdef_no, e->dest->index, 161 style, color, weight, 162 (e->flags & (EDGE_FAKE | EDGE_DFS_BACK)) ? "false" : "true"); 163 } 164 pp_flush (pp); 165 } 166 167 /* Draw all the basic blocks in the CFG in case loops are not available. 168 First compute a topological order of the blocks to get a good ranking of 169 the nodes. Then, if any nodes are not reachable from ENTRY, add them at 170 the end. */ 171 172 static void 173 draw_cfg_nodes_no_loops (pretty_printer *pp, struct function *fun) 174 { 175 int *rpo = XNEWVEC (int, n_basic_blocks_for_function (fun)); 176 int i, n; 177 sbitmap visited; 178 179 visited = sbitmap_alloc (last_basic_block); 180 bitmap_clear (visited); 181 182 /* FIXME: pre_and_rev_post_order_compute only works if fun == cfun. */ 183 n = pre_and_rev_post_order_compute (NULL, rpo, true); 184 for (i = 0; i < n; i++) 185 { 186 basic_block bb = BASIC_BLOCK (rpo[i]); 187 draw_cfg_node (pp, fun->funcdef_no, bb); 188 bitmap_set_bit (visited, bb->index); 189 } 190 free (rpo); 191 192 if (n != n_basic_blocks_for_function (fun)) 193 { 194 /* Some blocks are unreachable. We still want to dump them. */ 195 basic_block bb; 196 FOR_ALL_BB_FN (bb, fun) 197 if (! bitmap_bit_p (visited, bb->index)) 198 draw_cfg_node (pp, fun->funcdef_no, bb); 199 } 200 201 sbitmap_free (visited); 202 } 203 204 /* Draw all the basic blocks in LOOP. Print the blocks in breath-first 205 order to get a good ranking of the nodes. This function is recursive: 206 It first prints inner loops, then the body of LOOP itself. */ 207 208 static void 209 draw_cfg_nodes_for_loop (pretty_printer *pp, int funcdef_no, 210 struct loop *loop) 211 { 212 basic_block *body; 213 unsigned int i; 214 const char *fillcolors[3] = { "grey88", "grey77", "grey66" }; 215 216 if (loop->latch != EXIT_BLOCK_PTR) 217 pp_printf (pp, 218 "\tsubgraph cluster_%d_%d {\n" 219 "\tstyle=\"filled\";\n" 220 "\tcolor=\"darkgreen\";\n" 221 "\tfillcolor=\"%s\";\n" 222 "\tlabel=\"loop %d\";\n" 223 "\tlabeljust=l;\n" 224 "\tpenwidth=2;\n", 225 funcdef_no, loop->num, 226 fillcolors[(loop_depth (loop) - 1) % 3], 227 loop->num); 228 229 for (struct loop *inner = loop->inner; inner; inner = inner->next) 230 draw_cfg_nodes_for_loop (pp, funcdef_no, inner); 231 232 if (loop->latch == EXIT_BLOCK_PTR) 233 body = get_loop_body (loop); 234 else 235 body = get_loop_body_in_bfs_order (loop); 236 237 for (i = 0; i < loop->num_nodes; i++) 238 { 239 basic_block bb = body[i]; 240 if (bb->loop_father == loop) 241 draw_cfg_node (pp, funcdef_no, bb); 242 } 243 244 free (body); 245 246 if (loop->latch != EXIT_BLOCK_PTR) 247 pp_printf (pp, "\t}\n"); 248 } 249 250 /* Draw all the basic blocks in the CFG in case the loop tree is available. 251 All loop bodys are printed in clusters. */ 252 253 static void 254 draw_cfg_nodes (pretty_printer *pp, struct function *fun) 255 { 256 /* ??? This x_current_loops should be enapsulated. */ 257 if (fun->x_current_loops) 258 draw_cfg_nodes_for_loop (pp, fun->funcdef_no, 259 fun->x_current_loops->tree_root); 260 else 261 draw_cfg_nodes_no_loops (pp, fun); 262 } 263 264 /* Draw all edges in the CFG. Retreating edges are drawin as not 265 constraining, this makes the layout of the graph better. 266 (??? Calling mark_dfs_back may change the compiler's behavior when 267 dumping, but computing back edges here for ourselves is also not 268 desirable.) */ 269 270 static void 271 draw_cfg_edges (pretty_printer *pp, struct function *fun) 272 { 273 basic_block bb; 274 mark_dfs_back_edges (); 275 FOR_ALL_BB (bb) 276 draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb); 277 278 /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */ 279 pp_printf (pp, 280 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n " 281 "[style=\"invis\",constraint=true];\n", 282 fun->funcdef_no, ENTRY_BLOCK, 283 fun->funcdef_no, EXIT_BLOCK); 284 pp_flush (pp); 285 } 286 287 /* Print a graphical representation of the CFG of function FUN. 288 First print all basic blocks. Draw all edges at the end to get 289 subgraphs right for GraphViz, which requires nodes to be defined 290 before edges to cluster nodes properly. */ 291 292 void 293 print_graph_cfg (const char *base, struct function *fun) 294 { 295 const char *funcname = function_name (fun); 296 FILE *fp = open_graph_file (base, "a"); 297 pretty_printer *pp = init_graph_slim_pretty_print (fp); 298 pp_printf (pp, "subgraph \"%s\" {\n" 299 "\tcolor=\"black\";\n" 300 "\tlabel=\"%s\";\n", 301 funcname, funcname); 302 draw_cfg_nodes (pp, fun); 303 draw_cfg_edges (pp, fun); 304 pp_printf (pp, "}\n"); 305 pp_flush (pp); 306 fclose (fp); 307 } 308 309 /* Start the dump of a graph. */ 310 static void 311 start_graph_dump (FILE *fp, const char *base) 312 { 313 pretty_printer *pp = init_graph_slim_pretty_print (fp); 314 pp_string (pp, "digraph \""); 315 pp_write_text_to_stream (pp); 316 pp_string (pp, base); 317 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false); 318 pp_string (pp, "\" {\n"); 319 pp_string (pp, "overlap=false;\n"); 320 pp_flush (pp); 321 } 322 323 /* End the dump of a graph. */ 324 static void 325 end_graph_dump (FILE *fp) 326 { 327 fputs ("}\n", fp); 328 } 329 330 /* Similar as clean_dump_file, but this time for graph output files. */ 331 void 332 clean_graph_dump_file (const char *base) 333 { 334 FILE *fp = open_graph_file (base, "w"); 335 start_graph_dump (fp, base); 336 fclose (fp); 337 } 338 339 340 /* Do final work on the graph output file. */ 341 void 342 finish_graph_dump_file (const char *base) 343 { 344 FILE *fp = open_graph_file (base, "a"); 345 end_graph_dump (fp); 346 fclose (fp); 347 } 348