11debfc3dSmrg /* Output routines for graphical representation.
2*8feb0f0bSmrg Copyright (C) 1998-2020 Free Software Foundation, Inc.
31debfc3dSmrg Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
41debfc3dSmrg Rewritten for DOT output by Steven Bosscher, 2012.
51debfc3dSmrg
61debfc3dSmrg This file is part of GCC.
71debfc3dSmrg
81debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
91debfc3dSmrg the terms of the GNU General Public License as published by the Free
101debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
111debfc3dSmrg version.
121debfc3dSmrg
131debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
141debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
151debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
161debfc3dSmrg for more details.
171debfc3dSmrg
181debfc3dSmrg You should have received a copy of the GNU General Public License
191debfc3dSmrg along with GCC; see the file COPYING3. If not see
201debfc3dSmrg <http://www.gnu.org/licenses/>. */
211debfc3dSmrg
221debfc3dSmrg #include "config.h"
231debfc3dSmrg #include "system.h"
241debfc3dSmrg #include "coretypes.h"
251debfc3dSmrg #include "backend.h"
261debfc3dSmrg #include "cfghooks.h"
271debfc3dSmrg #include "pretty-print.h"
281debfc3dSmrg #include "diagnostic-core.h" /* for fatal_error */
291debfc3dSmrg #include "cfganal.h"
301debfc3dSmrg #include "cfgloop.h"
311debfc3dSmrg #include "graph.h"
321debfc3dSmrg #include "dumpfile.h"
331debfc3dSmrg
341debfc3dSmrg /* DOT files with the .dot extension are recognized as document templates
351debfc3dSmrg by a well-known piece of word processing software out of Redmond, WA.
361debfc3dSmrg Therefore some recommend using the .gv extension instead. Obstinately
371debfc3dSmrg ignore that recommendation... */
381debfc3dSmrg static const char *const graph_ext = ".dot";
391debfc3dSmrg
401debfc3dSmrg /* Open a file with MODE for dumping our graph to.
411debfc3dSmrg Return the file pointer. */
421debfc3dSmrg static FILE *
open_graph_file(const char * base,const char * mode)431debfc3dSmrg open_graph_file (const char *base, const char *mode)
441debfc3dSmrg {
451debfc3dSmrg size_t namelen = strlen (base);
461debfc3dSmrg size_t extlen = strlen (graph_ext) + 1;
471debfc3dSmrg char *buf = XALLOCAVEC (char, namelen + extlen);
481debfc3dSmrg FILE *fp;
491debfc3dSmrg
501debfc3dSmrg memcpy (buf, base, namelen);
511debfc3dSmrg memcpy (buf + namelen, graph_ext, extlen);
521debfc3dSmrg
531debfc3dSmrg fp = fopen (buf, mode);
541debfc3dSmrg if (fp == NULL)
55*8feb0f0bSmrg fatal_error (input_location, "cannot open %s: %m", buf);
561debfc3dSmrg
571debfc3dSmrg return fp;
581debfc3dSmrg }
591debfc3dSmrg
60*8feb0f0bSmrg /* Disable warnings about quoting issues in the pp_xxx calls below
61*8feb0f0bSmrg that (intentionally) don't follow GCC diagnostic conventions. */
62*8feb0f0bSmrg #if __GNUC__ >= 10
63*8feb0f0bSmrg # pragma GCC diagnostic push
64*8feb0f0bSmrg # pragma GCC diagnostic ignored "-Wformat-diag"
65*8feb0f0bSmrg #endif
66*8feb0f0bSmrg
671debfc3dSmrg /* Draw a basic block BB belonging to the function with FUNCDEF_NO
681debfc3dSmrg as its unique number. */
691debfc3dSmrg static void
draw_cfg_node(pretty_printer * pp,int funcdef_no,basic_block bb)701debfc3dSmrg draw_cfg_node (pretty_printer *pp, int funcdef_no, basic_block bb)
711debfc3dSmrg {
721debfc3dSmrg const char *shape;
731debfc3dSmrg const char *fillcolor;
741debfc3dSmrg
751debfc3dSmrg if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
761debfc3dSmrg {
771debfc3dSmrg shape = "Mdiamond";
781debfc3dSmrg fillcolor = "white";
791debfc3dSmrg }
801debfc3dSmrg else
811debfc3dSmrg {
821debfc3dSmrg shape = "record";
831debfc3dSmrg fillcolor =
841debfc3dSmrg BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink"
851debfc3dSmrg : BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue"
861debfc3dSmrg : "lightgrey";
871debfc3dSmrg }
881debfc3dSmrg
891debfc3dSmrg pp_printf (pp,
901debfc3dSmrg "\tfn_%d_basic_block_%d "
911debfc3dSmrg "[shape=%s,style=filled,fillcolor=%s,label=\"",
921debfc3dSmrg funcdef_no, bb->index, shape, fillcolor);
931debfc3dSmrg
941debfc3dSmrg if (bb->index == ENTRY_BLOCK)
951debfc3dSmrg pp_string (pp, "ENTRY");
961debfc3dSmrg else if (bb->index == EXIT_BLOCK)
971debfc3dSmrg pp_string (pp, "EXIT");
981debfc3dSmrg else
991debfc3dSmrg {
1001debfc3dSmrg pp_left_brace (pp);
1011debfc3dSmrg pp_write_text_to_stream (pp);
1021debfc3dSmrg dump_bb_for_graph (pp, bb);
1031debfc3dSmrg pp_right_brace (pp);
1041debfc3dSmrg }
1051debfc3dSmrg
1061debfc3dSmrg pp_string (pp, "\"];\n\n");
1071debfc3dSmrg pp_flush (pp);
1081debfc3dSmrg }
1091debfc3dSmrg
1101debfc3dSmrg /* Draw all successor edges of a basic block BB belonging to the function
1111debfc3dSmrg with FUNCDEF_NO as its unique number. */
1121debfc3dSmrg static void
draw_cfg_node_succ_edges(pretty_printer * pp,int funcdef_no,basic_block bb)1131debfc3dSmrg draw_cfg_node_succ_edges (pretty_printer *pp, int funcdef_no, basic_block bb)
1141debfc3dSmrg {
1151debfc3dSmrg edge e;
1161debfc3dSmrg edge_iterator ei;
1171debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
1181debfc3dSmrg {
1191debfc3dSmrg const char *style = "\"solid,bold\"";
1201debfc3dSmrg const char *color = "black";
1211debfc3dSmrg int weight = 10;
1221debfc3dSmrg
1231debfc3dSmrg if (e->flags & EDGE_FAKE)
1241debfc3dSmrg {
1251debfc3dSmrg style = "dotted";
1261debfc3dSmrg color = "green";
1271debfc3dSmrg weight = 0;
1281debfc3dSmrg }
1291debfc3dSmrg else if (e->flags & EDGE_DFS_BACK)
1301debfc3dSmrg {
1311debfc3dSmrg style = "\"dotted,bold\"";
1321debfc3dSmrg color = "blue";
1331debfc3dSmrg weight = 10;
1341debfc3dSmrg }
1351debfc3dSmrg else if (e->flags & EDGE_FALLTHRU)
1361debfc3dSmrg {
1371debfc3dSmrg color = "blue";
1381debfc3dSmrg weight = 100;
1391debfc3dSmrg }
1401debfc3dSmrg
1411debfc3dSmrg if (e->flags & EDGE_ABNORMAL)
1421debfc3dSmrg color = "red";
1431debfc3dSmrg
1441debfc3dSmrg pp_printf (pp,
1451debfc3dSmrg "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
146a2dc1f3fSmrg "[style=%s,color=%s,weight=%d,constraint=%s",
1471debfc3dSmrg funcdef_no, e->src->index,
1481debfc3dSmrg funcdef_no, e->dest->index,
1491debfc3dSmrg style, color, weight,
150a2dc1f3fSmrg (e->flags & (EDGE_FAKE | EDGE_DFS_BACK)) ? "false" : "true");
151a2dc1f3fSmrg if (e->probability.initialized_p ())
152a2dc1f3fSmrg pp_printf (pp, ",label=\"[%i%%]\"",
153a2dc1f3fSmrg e->probability.to_reg_br_prob_base ()
154a2dc1f3fSmrg * 100 / REG_BR_PROB_BASE);
155a2dc1f3fSmrg pp_printf (pp, "];\n");
1561debfc3dSmrg }
1571debfc3dSmrg pp_flush (pp);
1581debfc3dSmrg }
1591debfc3dSmrg
1601debfc3dSmrg /* Draw all the basic blocks in the CFG in case loops are not available.
1611debfc3dSmrg First compute a topological order of the blocks to get a good ranking of
1621debfc3dSmrg the nodes. Then, if any nodes are not reachable from ENTRY, add them at
1631debfc3dSmrg the end. */
1641debfc3dSmrg
1651debfc3dSmrg static void
draw_cfg_nodes_no_loops(pretty_printer * pp,struct function * fun)1661debfc3dSmrg draw_cfg_nodes_no_loops (pretty_printer *pp, struct function *fun)
1671debfc3dSmrg {
1681debfc3dSmrg int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun));
1691debfc3dSmrg int i, n;
1701debfc3dSmrg
1711debfc3dSmrg auto_sbitmap visited (last_basic_block_for_fn (cfun));
1721debfc3dSmrg bitmap_clear (visited);
1731debfc3dSmrg
1741debfc3dSmrg n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, true);
1751debfc3dSmrg for (i = n_basic_blocks_for_fn (fun) - n;
1761debfc3dSmrg i < n_basic_blocks_for_fn (fun); i++)
1771debfc3dSmrg {
1781debfc3dSmrg basic_block bb = BASIC_BLOCK_FOR_FN (cfun, rpo[i]);
1791debfc3dSmrg draw_cfg_node (pp, fun->funcdef_no, bb);
1801debfc3dSmrg bitmap_set_bit (visited, bb->index);
1811debfc3dSmrg }
1821debfc3dSmrg free (rpo);
1831debfc3dSmrg
1841debfc3dSmrg if (n != n_basic_blocks_for_fn (fun))
1851debfc3dSmrg {
1861debfc3dSmrg /* Some blocks are unreachable. We still want to dump them. */
1871debfc3dSmrg basic_block bb;
1881debfc3dSmrg FOR_ALL_BB_FN (bb, fun)
1891debfc3dSmrg if (! bitmap_bit_p (visited, bb->index))
1901debfc3dSmrg draw_cfg_node (pp, fun->funcdef_no, bb);
1911debfc3dSmrg }
1921debfc3dSmrg }
1931debfc3dSmrg
1941debfc3dSmrg /* Draw all the basic blocks in LOOP. Print the blocks in breath-first
1951debfc3dSmrg order to get a good ranking of the nodes. This function is recursive:
1961debfc3dSmrg It first prints inner loops, then the body of LOOP itself. */
1971debfc3dSmrg
1981debfc3dSmrg static void
draw_cfg_nodes_for_loop(pretty_printer * pp,int funcdef_no,class loop * loop)1991debfc3dSmrg draw_cfg_nodes_for_loop (pretty_printer *pp, int funcdef_no,
200*8feb0f0bSmrg class loop *loop)
2011debfc3dSmrg {
2021debfc3dSmrg basic_block *body;
2031debfc3dSmrg unsigned int i;
2041debfc3dSmrg const char *fillcolors[3] = { "grey88", "grey77", "grey66" };
2051debfc3dSmrg
2061debfc3dSmrg if (loop->header != NULL
2071debfc3dSmrg && loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
2081debfc3dSmrg pp_printf (pp,
2091debfc3dSmrg "\tsubgraph cluster_%d_%d {\n"
2101debfc3dSmrg "\tstyle=\"filled\";\n"
2111debfc3dSmrg "\tcolor=\"darkgreen\";\n"
2121debfc3dSmrg "\tfillcolor=\"%s\";\n"
2131debfc3dSmrg "\tlabel=\"loop %d\";\n"
2141debfc3dSmrg "\tlabeljust=l;\n"
2151debfc3dSmrg "\tpenwidth=2;\n",
2161debfc3dSmrg funcdef_no, loop->num,
2171debfc3dSmrg fillcolors[(loop_depth (loop) - 1) % 3],
2181debfc3dSmrg loop->num);
2191debfc3dSmrg
220*8feb0f0bSmrg for (class loop *inner = loop->inner; inner; inner = inner->next)
2211debfc3dSmrg draw_cfg_nodes_for_loop (pp, funcdef_no, inner);
2221debfc3dSmrg
2231debfc3dSmrg if (loop->header == NULL)
2241debfc3dSmrg return;
2251debfc3dSmrg
2261debfc3dSmrg if (loop->latch == EXIT_BLOCK_PTR_FOR_FN (cfun))
2271debfc3dSmrg body = get_loop_body (loop);
2281debfc3dSmrg else
2291debfc3dSmrg body = get_loop_body_in_bfs_order (loop);
2301debfc3dSmrg
2311debfc3dSmrg for (i = 0; i < loop->num_nodes; i++)
2321debfc3dSmrg {
2331debfc3dSmrg basic_block bb = body[i];
2341debfc3dSmrg if (bb->loop_father == loop)
2351debfc3dSmrg draw_cfg_node (pp, funcdef_no, bb);
2361debfc3dSmrg }
2371debfc3dSmrg
2381debfc3dSmrg free (body);
2391debfc3dSmrg
2401debfc3dSmrg if (loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
2411debfc3dSmrg pp_printf (pp, "\t}\n");
2421debfc3dSmrg }
2431debfc3dSmrg
2441debfc3dSmrg /* Draw all the basic blocks in the CFG in case the loop tree is available.
2451debfc3dSmrg All loop bodys are printed in clusters. */
2461debfc3dSmrg
2471debfc3dSmrg static void
draw_cfg_nodes(pretty_printer * pp,struct function * fun)2481debfc3dSmrg draw_cfg_nodes (pretty_printer *pp, struct function *fun)
2491debfc3dSmrg {
2501debfc3dSmrg if (loops_for_fn (fun))
2511debfc3dSmrg draw_cfg_nodes_for_loop (pp, fun->funcdef_no, get_loop (fun, 0));
2521debfc3dSmrg else
2531debfc3dSmrg draw_cfg_nodes_no_loops (pp, fun);
2541debfc3dSmrg }
2551debfc3dSmrg
2561debfc3dSmrg /* Draw all edges in the CFG. Retreating edges are drawin as not
257a2dc1f3fSmrg constraining, this makes the layout of the graph better. */
2581debfc3dSmrg
2591debfc3dSmrg static void
draw_cfg_edges(pretty_printer * pp,struct function * fun)2601debfc3dSmrg draw_cfg_edges (pretty_printer *pp, struct function *fun)
2611debfc3dSmrg {
2621debfc3dSmrg basic_block bb;
263a2dc1f3fSmrg
264a2dc1f3fSmrg /* Save EDGE_DFS_BACK flag to dfs_back. */
265a2dc1f3fSmrg auto_bitmap dfs_back;
266a2dc1f3fSmrg edge e;
267a2dc1f3fSmrg edge_iterator ei;
268a2dc1f3fSmrg unsigned int idx = 0;
269a2dc1f3fSmrg FOR_EACH_BB_FN (bb, cfun)
270a2dc1f3fSmrg FOR_EACH_EDGE (e, ei, bb->succs)
271a2dc1f3fSmrg {
272a2dc1f3fSmrg if (e->flags & EDGE_DFS_BACK)
273a2dc1f3fSmrg bitmap_set_bit (dfs_back, idx);
274a2dc1f3fSmrg idx++;
275a2dc1f3fSmrg }
276a2dc1f3fSmrg
2771debfc3dSmrg mark_dfs_back_edges ();
2781debfc3dSmrg FOR_ALL_BB_FN (bb, cfun)
2791debfc3dSmrg draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb);
2801debfc3dSmrg
281a2dc1f3fSmrg /* Restore EDGE_DFS_BACK flag from dfs_back. */
282a2dc1f3fSmrg idx = 0;
283a2dc1f3fSmrg FOR_EACH_BB_FN (bb, cfun)
284a2dc1f3fSmrg FOR_EACH_EDGE (e, ei, bb->succs)
285a2dc1f3fSmrg {
286a2dc1f3fSmrg if (bitmap_bit_p (dfs_back, idx))
287a2dc1f3fSmrg e->flags |= EDGE_DFS_BACK;
288a2dc1f3fSmrg else
289a2dc1f3fSmrg e->flags &= ~EDGE_DFS_BACK;
290a2dc1f3fSmrg idx++;
291a2dc1f3fSmrg }
292a2dc1f3fSmrg
2931debfc3dSmrg /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */
2941debfc3dSmrg pp_printf (pp,
2951debfc3dSmrg "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
2961debfc3dSmrg "[style=\"invis\",constraint=true];\n",
2971debfc3dSmrg fun->funcdef_no, ENTRY_BLOCK,
2981debfc3dSmrg fun->funcdef_no, EXIT_BLOCK);
2991debfc3dSmrg pp_flush (pp);
3001debfc3dSmrg }
3011debfc3dSmrg
3021debfc3dSmrg /* Print a graphical representation of the CFG of function FUN.
3031debfc3dSmrg First print all basic blocks. Draw all edges at the end to get
3041debfc3dSmrg subgraphs right for GraphViz, which requires nodes to be defined
3051debfc3dSmrg before edges to cluster nodes properly. */
3061debfc3dSmrg
3071debfc3dSmrg void DEBUG_FUNCTION
print_graph_cfg(FILE * fp,struct function * fun)3081debfc3dSmrg print_graph_cfg (FILE *fp, struct function *fun)
3091debfc3dSmrg {
3101debfc3dSmrg pretty_printer graph_slim_pp;
3111debfc3dSmrg graph_slim_pp.buffer->stream = fp;
3121debfc3dSmrg pretty_printer *const pp = &graph_slim_pp;
3131debfc3dSmrg const char *funcname = function_name (fun);
3141debfc3dSmrg pp_printf (pp, "subgraph \"cluster_%s\" {\n"
3151debfc3dSmrg "\tstyle=\"dashed\";\n"
3161debfc3dSmrg "\tcolor=\"black\";\n"
3171debfc3dSmrg "\tlabel=\"%s ()\";\n",
3181debfc3dSmrg funcname, funcname);
3191debfc3dSmrg draw_cfg_nodes (pp, fun);
3201debfc3dSmrg draw_cfg_edges (pp, fun);
3211debfc3dSmrg pp_printf (pp, "}\n");
3221debfc3dSmrg pp_flush (pp);
3231debfc3dSmrg }
3241debfc3dSmrg
3251debfc3dSmrg /* Overload with additional flag argument. */
3261debfc3dSmrg
3271debfc3dSmrg void DEBUG_FUNCTION
print_graph_cfg(FILE * fp,struct function * fun,dump_flags_t flags)328a2dc1f3fSmrg print_graph_cfg (FILE *fp, struct function *fun, dump_flags_t flags)
3291debfc3dSmrg {
330a2dc1f3fSmrg dump_flags_t saved_dump_flags = dump_flags;
3311debfc3dSmrg dump_flags = flags;
3321debfc3dSmrg print_graph_cfg (fp, fun);
3331debfc3dSmrg dump_flags = saved_dump_flags;
3341debfc3dSmrg }
3351debfc3dSmrg
3361debfc3dSmrg
3371debfc3dSmrg /* Print a graphical representation of the CFG of function FUN.
3381debfc3dSmrg First print all basic blocks. Draw all edges at the end to get
3391debfc3dSmrg subgraphs right for GraphViz, which requires nodes to be defined
3401debfc3dSmrg before edges to cluster nodes properly. */
3411debfc3dSmrg
3421debfc3dSmrg void
print_graph_cfg(const char * base,struct function * fun)3431debfc3dSmrg print_graph_cfg (const char *base, struct function *fun)
3441debfc3dSmrg {
3451debfc3dSmrg FILE *fp = open_graph_file (base, "a");
3461debfc3dSmrg print_graph_cfg (fp, fun);
3471debfc3dSmrg fclose (fp);
3481debfc3dSmrg }
3491debfc3dSmrg
3501debfc3dSmrg /* Start the dump of a graph. */
3511debfc3dSmrg static void
start_graph_dump(FILE * fp,const char * base)3521debfc3dSmrg start_graph_dump (FILE *fp, const char *base)
3531debfc3dSmrg {
3541debfc3dSmrg pretty_printer graph_slim_pp;
3551debfc3dSmrg graph_slim_pp.buffer->stream = fp;
3561debfc3dSmrg pretty_printer *const pp = &graph_slim_pp;
3571debfc3dSmrg pp_string (pp, "digraph \"");
3581debfc3dSmrg pp_write_text_to_stream (pp);
3591debfc3dSmrg pp_string (pp, base);
3601debfc3dSmrg pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
3611debfc3dSmrg pp_string (pp, "\" {\n");
3621debfc3dSmrg pp_string (pp, "overlap=false;\n");
3631debfc3dSmrg pp_flush (pp);
3641debfc3dSmrg }
3651debfc3dSmrg
3661debfc3dSmrg /* End the dump of a graph. */
3671debfc3dSmrg static void
end_graph_dump(FILE * fp)3681debfc3dSmrg end_graph_dump (FILE *fp)
3691debfc3dSmrg {
3701debfc3dSmrg fputs ("}\n", fp);
3711debfc3dSmrg }
3721debfc3dSmrg
3731debfc3dSmrg /* Similar as clean_dump_file, but this time for graph output files. */
3741debfc3dSmrg void
clean_graph_dump_file(const char * base)3751debfc3dSmrg clean_graph_dump_file (const char *base)
3761debfc3dSmrg {
3771debfc3dSmrg FILE *fp = open_graph_file (base, "w");
3781debfc3dSmrg start_graph_dump (fp, base);
3791debfc3dSmrg fclose (fp);
3801debfc3dSmrg }
3811debfc3dSmrg
3821debfc3dSmrg
3831debfc3dSmrg /* Do final work on the graph output file. */
3841debfc3dSmrg void
finish_graph_dump_file(const char * base)3851debfc3dSmrg finish_graph_dump_file (const char *base)
3861debfc3dSmrg {
3871debfc3dSmrg FILE *fp = open_graph_file (base, "a");
3881debfc3dSmrg end_graph_dump (fp);
3891debfc3dSmrg fclose (fp);
3901debfc3dSmrg }
391*8feb0f0bSmrg
392*8feb0f0bSmrg #if __GNUC__ >= 10
393*8feb0f0bSmrg # pragma GCC diagnostic pop
394*8feb0f0bSmrg #endif
395