1*38fd1498Szrj /* Output routines for graphical representation.
2*38fd1498Szrj Copyright (C) 1998-2018 Free Software Foundation, Inc.
3*38fd1498Szrj Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
4*38fd1498Szrj Rewritten for DOT output by Steven Bosscher, 2012.
5*38fd1498Szrj
6*38fd1498Szrj This file is part of GCC.
7*38fd1498Szrj
8*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
9*38fd1498Szrj the terms of the GNU General Public License as published by the Free
10*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
11*38fd1498Szrj version.
12*38fd1498Szrj
13*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
15*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16*38fd1498Szrj for more details.
17*38fd1498Szrj
18*38fd1498Szrj You should have received a copy of the GNU General Public License
19*38fd1498Szrj along with GCC; see the file COPYING3. If not see
20*38fd1498Szrj <http://www.gnu.org/licenses/>. */
21*38fd1498Szrj
22*38fd1498Szrj #include "config.h"
23*38fd1498Szrj #include "system.h"
24*38fd1498Szrj #include "coretypes.h"
25*38fd1498Szrj #include "backend.h"
26*38fd1498Szrj #include "cfghooks.h"
27*38fd1498Szrj #include "pretty-print.h"
28*38fd1498Szrj #include "diagnostic-core.h" /* for fatal_error */
29*38fd1498Szrj #include "cfganal.h"
30*38fd1498Szrj #include "cfgloop.h"
31*38fd1498Szrj #include "graph.h"
32*38fd1498Szrj #include "dumpfile.h"
33*38fd1498Szrj
34*38fd1498Szrj /* DOT files with the .dot extension are recognized as document templates
35*38fd1498Szrj by a well-known piece of word processing software out of Redmond, WA.
36*38fd1498Szrj Therefore some recommend using the .gv extension instead. Obstinately
37*38fd1498Szrj ignore that recommendation... */
38*38fd1498Szrj static const char *const graph_ext = ".dot";
39*38fd1498Szrj
40*38fd1498Szrj /* Open a file with MODE for dumping our graph to.
41*38fd1498Szrj Return the file pointer. */
42*38fd1498Szrj static FILE *
open_graph_file(const char * base,const char * mode)43*38fd1498Szrj open_graph_file (const char *base, const char *mode)
44*38fd1498Szrj {
45*38fd1498Szrj size_t namelen = strlen (base);
46*38fd1498Szrj size_t extlen = strlen (graph_ext) + 1;
47*38fd1498Szrj char *buf = XALLOCAVEC (char, namelen + extlen);
48*38fd1498Szrj FILE *fp;
49*38fd1498Szrj
50*38fd1498Szrj memcpy (buf, base, namelen);
51*38fd1498Szrj memcpy (buf + namelen, graph_ext, extlen);
52*38fd1498Szrj
53*38fd1498Szrj fp = fopen (buf, mode);
54*38fd1498Szrj if (fp == NULL)
55*38fd1498Szrj fatal_error (input_location, "can%'t open %s: %m", buf);
56*38fd1498Szrj
57*38fd1498Szrj return fp;
58*38fd1498Szrj }
59*38fd1498Szrj
60*38fd1498Szrj /* Draw a basic block BB belonging to the function with FUNCDEF_NO
61*38fd1498Szrj as its unique number. */
62*38fd1498Szrj static void
draw_cfg_node(pretty_printer * pp,int funcdef_no,basic_block bb)63*38fd1498Szrj draw_cfg_node (pretty_printer *pp, int funcdef_no, basic_block bb)
64*38fd1498Szrj {
65*38fd1498Szrj const char *shape;
66*38fd1498Szrj const char *fillcolor;
67*38fd1498Szrj
68*38fd1498Szrj if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
69*38fd1498Szrj {
70*38fd1498Szrj shape = "Mdiamond";
71*38fd1498Szrj fillcolor = "white";
72*38fd1498Szrj }
73*38fd1498Szrj else
74*38fd1498Szrj {
75*38fd1498Szrj shape = "record";
76*38fd1498Szrj fillcolor =
77*38fd1498Szrj BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink"
78*38fd1498Szrj : BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue"
79*38fd1498Szrj : "lightgrey";
80*38fd1498Szrj }
81*38fd1498Szrj
82*38fd1498Szrj pp_printf (pp,
83*38fd1498Szrj "\tfn_%d_basic_block_%d "
84*38fd1498Szrj "[shape=%s,style=filled,fillcolor=%s,label=\"",
85*38fd1498Szrj funcdef_no, bb->index, shape, fillcolor);
86*38fd1498Szrj
87*38fd1498Szrj if (bb->index == ENTRY_BLOCK)
88*38fd1498Szrj pp_string (pp, "ENTRY");
89*38fd1498Szrj else if (bb->index == EXIT_BLOCK)
90*38fd1498Szrj pp_string (pp, "EXIT");
91*38fd1498Szrj else
92*38fd1498Szrj {
93*38fd1498Szrj pp_left_brace (pp);
94*38fd1498Szrj pp_write_text_to_stream (pp);
95*38fd1498Szrj dump_bb_for_graph (pp, bb);
96*38fd1498Szrj pp_right_brace (pp);
97*38fd1498Szrj }
98*38fd1498Szrj
99*38fd1498Szrj pp_string (pp, "\"];\n\n");
100*38fd1498Szrj pp_flush (pp);
101*38fd1498Szrj }
102*38fd1498Szrj
103*38fd1498Szrj /* Draw all successor edges of a basic block BB belonging to the function
104*38fd1498Szrj with FUNCDEF_NO as its unique number. */
105*38fd1498Szrj static void
draw_cfg_node_succ_edges(pretty_printer * pp,int funcdef_no,basic_block bb)106*38fd1498Szrj draw_cfg_node_succ_edges (pretty_printer *pp, int funcdef_no, basic_block bb)
107*38fd1498Szrj {
108*38fd1498Szrj edge e;
109*38fd1498Szrj edge_iterator ei;
110*38fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
111*38fd1498Szrj {
112*38fd1498Szrj const char *style = "\"solid,bold\"";
113*38fd1498Szrj const char *color = "black";
114*38fd1498Szrj int weight = 10;
115*38fd1498Szrj
116*38fd1498Szrj if (e->flags & EDGE_FAKE)
117*38fd1498Szrj {
118*38fd1498Szrj style = "dotted";
119*38fd1498Szrj color = "green";
120*38fd1498Szrj weight = 0;
121*38fd1498Szrj }
122*38fd1498Szrj else if (e->flags & EDGE_DFS_BACK)
123*38fd1498Szrj {
124*38fd1498Szrj style = "\"dotted,bold\"";
125*38fd1498Szrj color = "blue";
126*38fd1498Szrj weight = 10;
127*38fd1498Szrj }
128*38fd1498Szrj else if (e->flags & EDGE_FALLTHRU)
129*38fd1498Szrj {
130*38fd1498Szrj color = "blue";
131*38fd1498Szrj weight = 100;
132*38fd1498Szrj }
133*38fd1498Szrj
134*38fd1498Szrj if (e->flags & EDGE_ABNORMAL)
135*38fd1498Szrj color = "red";
136*38fd1498Szrj
137*38fd1498Szrj pp_printf (pp,
138*38fd1498Szrj "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
139*38fd1498Szrj "[style=%s,color=%s,weight=%d,constraint=%s",
140*38fd1498Szrj funcdef_no, e->src->index,
141*38fd1498Szrj funcdef_no, e->dest->index,
142*38fd1498Szrj style, color, weight,
143*38fd1498Szrj (e->flags & (EDGE_FAKE | EDGE_DFS_BACK)) ? "false" : "true");
144*38fd1498Szrj if (e->probability.initialized_p ())
145*38fd1498Szrj pp_printf (pp, ",label=\"[%i%%]\"",
146*38fd1498Szrj e->probability.to_reg_br_prob_base ()
147*38fd1498Szrj * 100 / REG_BR_PROB_BASE);
148*38fd1498Szrj pp_printf (pp, "];\n");
149*38fd1498Szrj }
150*38fd1498Szrj pp_flush (pp);
151*38fd1498Szrj }
152*38fd1498Szrj
153*38fd1498Szrj /* Draw all the basic blocks in the CFG in case loops are not available.
154*38fd1498Szrj First compute a topological order of the blocks to get a good ranking of
155*38fd1498Szrj the nodes. Then, if any nodes are not reachable from ENTRY, add them at
156*38fd1498Szrj the end. */
157*38fd1498Szrj
158*38fd1498Szrj static void
draw_cfg_nodes_no_loops(pretty_printer * pp,struct function * fun)159*38fd1498Szrj draw_cfg_nodes_no_loops (pretty_printer *pp, struct function *fun)
160*38fd1498Szrj {
161*38fd1498Szrj int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun));
162*38fd1498Szrj int i, n;
163*38fd1498Szrj
164*38fd1498Szrj auto_sbitmap visited (last_basic_block_for_fn (cfun));
165*38fd1498Szrj bitmap_clear (visited);
166*38fd1498Szrj
167*38fd1498Szrj n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, true);
168*38fd1498Szrj for (i = n_basic_blocks_for_fn (fun) - n;
169*38fd1498Szrj i < n_basic_blocks_for_fn (fun); i++)
170*38fd1498Szrj {
171*38fd1498Szrj basic_block bb = BASIC_BLOCK_FOR_FN (cfun, rpo[i]);
172*38fd1498Szrj draw_cfg_node (pp, fun->funcdef_no, bb);
173*38fd1498Szrj bitmap_set_bit (visited, bb->index);
174*38fd1498Szrj }
175*38fd1498Szrj free (rpo);
176*38fd1498Szrj
177*38fd1498Szrj if (n != n_basic_blocks_for_fn (fun))
178*38fd1498Szrj {
179*38fd1498Szrj /* Some blocks are unreachable. We still want to dump them. */
180*38fd1498Szrj basic_block bb;
181*38fd1498Szrj FOR_ALL_BB_FN (bb, fun)
182*38fd1498Szrj if (! bitmap_bit_p (visited, bb->index))
183*38fd1498Szrj draw_cfg_node (pp, fun->funcdef_no, bb);
184*38fd1498Szrj }
185*38fd1498Szrj }
186*38fd1498Szrj
187*38fd1498Szrj /* Draw all the basic blocks in LOOP. Print the blocks in breath-first
188*38fd1498Szrj order to get a good ranking of the nodes. This function is recursive:
189*38fd1498Szrj It first prints inner loops, then the body of LOOP itself. */
190*38fd1498Szrj
191*38fd1498Szrj static void
draw_cfg_nodes_for_loop(pretty_printer * pp,int funcdef_no,struct loop * loop)192*38fd1498Szrj draw_cfg_nodes_for_loop (pretty_printer *pp, int funcdef_no,
193*38fd1498Szrj struct loop *loop)
194*38fd1498Szrj {
195*38fd1498Szrj basic_block *body;
196*38fd1498Szrj unsigned int i;
197*38fd1498Szrj const char *fillcolors[3] = { "grey88", "grey77", "grey66" };
198*38fd1498Szrj
199*38fd1498Szrj if (loop->header != NULL
200*38fd1498Szrj && loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
201*38fd1498Szrj pp_printf (pp,
202*38fd1498Szrj "\tsubgraph cluster_%d_%d {\n"
203*38fd1498Szrj "\tstyle=\"filled\";\n"
204*38fd1498Szrj "\tcolor=\"darkgreen\";\n"
205*38fd1498Szrj "\tfillcolor=\"%s\";\n"
206*38fd1498Szrj "\tlabel=\"loop %d\";\n"
207*38fd1498Szrj "\tlabeljust=l;\n"
208*38fd1498Szrj "\tpenwidth=2;\n",
209*38fd1498Szrj funcdef_no, loop->num,
210*38fd1498Szrj fillcolors[(loop_depth (loop) - 1) % 3],
211*38fd1498Szrj loop->num);
212*38fd1498Szrj
213*38fd1498Szrj for (struct loop *inner = loop->inner; inner; inner = inner->next)
214*38fd1498Szrj draw_cfg_nodes_for_loop (pp, funcdef_no, inner);
215*38fd1498Szrj
216*38fd1498Szrj if (loop->header == NULL)
217*38fd1498Szrj return;
218*38fd1498Szrj
219*38fd1498Szrj if (loop->latch == EXIT_BLOCK_PTR_FOR_FN (cfun))
220*38fd1498Szrj body = get_loop_body (loop);
221*38fd1498Szrj else
222*38fd1498Szrj body = get_loop_body_in_bfs_order (loop);
223*38fd1498Szrj
224*38fd1498Szrj for (i = 0; i < loop->num_nodes; i++)
225*38fd1498Szrj {
226*38fd1498Szrj basic_block bb = body[i];
227*38fd1498Szrj if (bb->loop_father == loop)
228*38fd1498Szrj draw_cfg_node (pp, funcdef_no, bb);
229*38fd1498Szrj }
230*38fd1498Szrj
231*38fd1498Szrj free (body);
232*38fd1498Szrj
233*38fd1498Szrj if (loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
234*38fd1498Szrj pp_printf (pp, "\t}\n");
235*38fd1498Szrj }
236*38fd1498Szrj
237*38fd1498Szrj /* Draw all the basic blocks in the CFG in case the loop tree is available.
238*38fd1498Szrj All loop bodys are printed in clusters. */
239*38fd1498Szrj
240*38fd1498Szrj static void
draw_cfg_nodes(pretty_printer * pp,struct function * fun)241*38fd1498Szrj draw_cfg_nodes (pretty_printer *pp, struct function *fun)
242*38fd1498Szrj {
243*38fd1498Szrj if (loops_for_fn (fun))
244*38fd1498Szrj draw_cfg_nodes_for_loop (pp, fun->funcdef_no, get_loop (fun, 0));
245*38fd1498Szrj else
246*38fd1498Szrj draw_cfg_nodes_no_loops (pp, fun);
247*38fd1498Szrj }
248*38fd1498Szrj
249*38fd1498Szrj /* Draw all edges in the CFG. Retreating edges are drawin as not
250*38fd1498Szrj constraining, this makes the layout of the graph better. */
251*38fd1498Szrj
252*38fd1498Szrj static void
draw_cfg_edges(pretty_printer * pp,struct function * fun)253*38fd1498Szrj draw_cfg_edges (pretty_printer *pp, struct function *fun)
254*38fd1498Szrj {
255*38fd1498Szrj basic_block bb;
256*38fd1498Szrj
257*38fd1498Szrj /* Save EDGE_DFS_BACK flag to dfs_back. */
258*38fd1498Szrj auto_bitmap dfs_back;
259*38fd1498Szrj edge e;
260*38fd1498Szrj edge_iterator ei;
261*38fd1498Szrj unsigned int idx = 0;
262*38fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
263*38fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
264*38fd1498Szrj {
265*38fd1498Szrj if (e->flags & EDGE_DFS_BACK)
266*38fd1498Szrj bitmap_set_bit (dfs_back, idx);
267*38fd1498Szrj idx++;
268*38fd1498Szrj }
269*38fd1498Szrj
270*38fd1498Szrj mark_dfs_back_edges ();
271*38fd1498Szrj FOR_ALL_BB_FN (bb, cfun)
272*38fd1498Szrj draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb);
273*38fd1498Szrj
274*38fd1498Szrj /* Restore EDGE_DFS_BACK flag from dfs_back. */
275*38fd1498Szrj idx = 0;
276*38fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
277*38fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
278*38fd1498Szrj {
279*38fd1498Szrj if (bitmap_bit_p (dfs_back, idx))
280*38fd1498Szrj e->flags |= EDGE_DFS_BACK;
281*38fd1498Szrj else
282*38fd1498Szrj e->flags &= ~EDGE_DFS_BACK;
283*38fd1498Szrj idx++;
284*38fd1498Szrj }
285*38fd1498Szrj
286*38fd1498Szrj /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */
287*38fd1498Szrj pp_printf (pp,
288*38fd1498Szrj "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
289*38fd1498Szrj "[style=\"invis\",constraint=true];\n",
290*38fd1498Szrj fun->funcdef_no, ENTRY_BLOCK,
291*38fd1498Szrj fun->funcdef_no, EXIT_BLOCK);
292*38fd1498Szrj pp_flush (pp);
293*38fd1498Szrj }
294*38fd1498Szrj
295*38fd1498Szrj /* Print a graphical representation of the CFG of function FUN.
296*38fd1498Szrj First print all basic blocks. Draw all edges at the end to get
297*38fd1498Szrj subgraphs right for GraphViz, which requires nodes to be defined
298*38fd1498Szrj before edges to cluster nodes properly. */
299*38fd1498Szrj
300*38fd1498Szrj void DEBUG_FUNCTION
print_graph_cfg(FILE * fp,struct function * fun)301*38fd1498Szrj print_graph_cfg (FILE *fp, struct function *fun)
302*38fd1498Szrj {
303*38fd1498Szrj pretty_printer graph_slim_pp;
304*38fd1498Szrj graph_slim_pp.buffer->stream = fp;
305*38fd1498Szrj pretty_printer *const pp = &graph_slim_pp;
306*38fd1498Szrj const char *funcname = function_name (fun);
307*38fd1498Szrj pp_printf (pp, "subgraph \"cluster_%s\" {\n"
308*38fd1498Szrj "\tstyle=\"dashed\";\n"
309*38fd1498Szrj "\tcolor=\"black\";\n"
310*38fd1498Szrj "\tlabel=\"%s ()\";\n",
311*38fd1498Szrj funcname, funcname);
312*38fd1498Szrj draw_cfg_nodes (pp, fun);
313*38fd1498Szrj draw_cfg_edges (pp, fun);
314*38fd1498Szrj pp_printf (pp, "}\n");
315*38fd1498Szrj pp_flush (pp);
316*38fd1498Szrj }
317*38fd1498Szrj
318*38fd1498Szrj /* Overload with additional flag argument. */
319*38fd1498Szrj
320*38fd1498Szrj void DEBUG_FUNCTION
print_graph_cfg(FILE * fp,struct function * fun,dump_flags_t flags)321*38fd1498Szrj print_graph_cfg (FILE *fp, struct function *fun, dump_flags_t flags)
322*38fd1498Szrj {
323*38fd1498Szrj dump_flags_t saved_dump_flags = dump_flags;
324*38fd1498Szrj dump_flags = flags;
325*38fd1498Szrj print_graph_cfg (fp, fun);
326*38fd1498Szrj dump_flags = saved_dump_flags;
327*38fd1498Szrj }
328*38fd1498Szrj
329*38fd1498Szrj
330*38fd1498Szrj /* Print a graphical representation of the CFG of function FUN.
331*38fd1498Szrj First print all basic blocks. Draw all edges at the end to get
332*38fd1498Szrj subgraphs right for GraphViz, which requires nodes to be defined
333*38fd1498Szrj before edges to cluster nodes properly. */
334*38fd1498Szrj
335*38fd1498Szrj void
print_graph_cfg(const char * base,struct function * fun)336*38fd1498Szrj print_graph_cfg (const char *base, struct function *fun)
337*38fd1498Szrj {
338*38fd1498Szrj FILE *fp = open_graph_file (base, "a");
339*38fd1498Szrj print_graph_cfg (fp, fun);
340*38fd1498Szrj fclose (fp);
341*38fd1498Szrj }
342*38fd1498Szrj
343*38fd1498Szrj /* Start the dump of a graph. */
344*38fd1498Szrj static void
start_graph_dump(FILE * fp,const char * base)345*38fd1498Szrj start_graph_dump (FILE *fp, const char *base)
346*38fd1498Szrj {
347*38fd1498Szrj pretty_printer graph_slim_pp;
348*38fd1498Szrj graph_slim_pp.buffer->stream = fp;
349*38fd1498Szrj pretty_printer *const pp = &graph_slim_pp;
350*38fd1498Szrj pp_string (pp, "digraph \"");
351*38fd1498Szrj pp_write_text_to_stream (pp);
352*38fd1498Szrj pp_string (pp, base);
353*38fd1498Szrj pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
354*38fd1498Szrj pp_string (pp, "\" {\n");
355*38fd1498Szrj pp_string (pp, "overlap=false;\n");
356*38fd1498Szrj pp_flush (pp);
357*38fd1498Szrj }
358*38fd1498Szrj
359*38fd1498Szrj /* End the dump of a graph. */
360*38fd1498Szrj static void
end_graph_dump(FILE * fp)361*38fd1498Szrj end_graph_dump (FILE *fp)
362*38fd1498Szrj {
363*38fd1498Szrj fputs ("}\n", fp);
364*38fd1498Szrj }
365*38fd1498Szrj
366*38fd1498Szrj /* Similar as clean_dump_file, but this time for graph output files. */
367*38fd1498Szrj void
clean_graph_dump_file(const char * base)368*38fd1498Szrj clean_graph_dump_file (const char *base)
369*38fd1498Szrj {
370*38fd1498Szrj FILE *fp = open_graph_file (base, "w");
371*38fd1498Szrj start_graph_dump (fp, base);
372*38fd1498Szrj fclose (fp);
373*38fd1498Szrj }
374*38fd1498Szrj
375*38fd1498Szrj
376*38fd1498Szrj /* Do final work on the graph output file. */
377*38fd1498Szrj void
finish_graph_dump_file(const char * base)378*38fd1498Szrj finish_graph_dump_file (const char *base)
379*38fd1498Szrj {
380*38fd1498Szrj FILE *fp = open_graph_file (base, "a");
381*38fd1498Szrj end_graph_dump (fp);
382*38fd1498Szrj fclose (fp);
383*38fd1498Szrj }
384