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