xref: /dflybsd-src/contrib/gcc-8.0/gcc/graph.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
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