Mercurial > hg > CbC > CbC_gcc
annotate gcc/graph.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
rev | line source |
---|---|
0 | 1 /* Output routines for graphical representation. |
131 | 2 Copyright (C) 1998-2018 Free Software Foundation, Inc. |
0 | 3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. |
111 | 4 Rewritten for DOT output by Steven Bosscher, 2012. |
0 | 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 | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
22 #include "config.h" |
0 | 23 #include "system.h" |
24 #include "coretypes.h" | |
111 | 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" | |
0 | 31 #include "graph.h" |
111 | 32 #include "dumpfile.h" |
0 | 33 |
111 | 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"; | |
0 | 39 |
111 | 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) | |
0 | 44 { |
45 size_t namelen = strlen (base); | |
111 | 46 size_t extlen = strlen (graph_ext) + 1; |
0 | 47 char *buf = XALLOCAVEC (char, namelen + extlen); |
48 FILE *fp; | |
49 | |
50 memcpy (buf, base, namelen); | |
111 | 51 memcpy (buf + namelen, graph_ext, extlen); |
0 | 52 |
111 | 53 fp = fopen (buf, mode); |
0 | 54 if (fp == NULL) |
111 | 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", | |
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 if (e->probability.initialized_p ()) | |
145 pp_printf (pp, ",label=\"[%i%%]\"", | |
146 e->probability.to_reg_br_prob_base () | |
147 * 100 / REG_BR_PROB_BASE); | |
148 pp_printf (pp, "];\n"); | |
149 } | |
150 pp_flush (pp); | |
151 } | |
152 | |
153 /* Draw all the basic blocks in the CFG in case loops are not available. | |
154 First compute a topological order of the blocks to get a good ranking of | |
155 the nodes. Then, if any nodes are not reachable from ENTRY, add them at | |
156 the end. */ | |
157 | |
158 static void | |
159 draw_cfg_nodes_no_loops (pretty_printer *pp, struct function *fun) | |
160 { | |
161 int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun)); | |
162 int i, n; | |
163 | |
164 auto_sbitmap visited (last_basic_block_for_fn (cfun)); | |
165 bitmap_clear (visited); | |
166 | |
167 n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, true); | |
168 for (i = n_basic_blocks_for_fn (fun) - n; | |
169 i < n_basic_blocks_for_fn (fun); i++) | |
170 { | |
171 basic_block bb = BASIC_BLOCK_FOR_FN (cfun, rpo[i]); | |
172 draw_cfg_node (pp, fun->funcdef_no, bb); | |
173 bitmap_set_bit (visited, bb->index); | |
174 } | |
175 free (rpo); | |
176 | |
177 if (n != n_basic_blocks_for_fn (fun)) | |
178 { | |
179 /* Some blocks are unreachable. We still want to dump them. */ | |
180 basic_block bb; | |
181 FOR_ALL_BB_FN (bb, fun) | |
182 if (! bitmap_bit_p (visited, bb->index)) | |
183 draw_cfg_node (pp, fun->funcdef_no, bb); | |
184 } | |
185 } | |
186 | |
187 /* Draw all the basic blocks in LOOP. Print the blocks in breath-first | |
188 order to get a good ranking of the nodes. This function is recursive: | |
189 It first prints inner loops, then the body of LOOP itself. */ | |
190 | |
191 static void | |
192 draw_cfg_nodes_for_loop (pretty_printer *pp, int funcdef_no, | |
193 struct loop *loop) | |
194 { | |
195 basic_block *body; | |
196 unsigned int i; | |
197 const char *fillcolors[3] = { "grey88", "grey77", "grey66" }; | |
198 | |
199 if (loop->header != NULL | |
200 && loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun)) | |
201 pp_printf (pp, | |
202 "\tsubgraph cluster_%d_%d {\n" | |
203 "\tstyle=\"filled\";\n" | |
204 "\tcolor=\"darkgreen\";\n" | |
205 "\tfillcolor=\"%s\";\n" | |
206 "\tlabel=\"loop %d\";\n" | |
207 "\tlabeljust=l;\n" | |
208 "\tpenwidth=2;\n", | |
209 funcdef_no, loop->num, | |
210 fillcolors[(loop_depth (loop) - 1) % 3], | |
211 loop->num); | |
0 | 212 |
111 | 213 for (struct loop *inner = loop->inner; inner; inner = inner->next) |
214 draw_cfg_nodes_for_loop (pp, funcdef_no, inner); | |
215 | |
216 if (loop->header == NULL) | |
217 return; | |
218 | |
219 if (loop->latch == EXIT_BLOCK_PTR_FOR_FN (cfun)) | |
220 body = get_loop_body (loop); | |
221 else | |
222 body = get_loop_body_in_bfs_order (loop); | |
223 | |
224 for (i = 0; i < loop->num_nodes; i++) | |
225 { | |
226 basic_block bb = body[i]; | |
227 if (bb->loop_father == loop) | |
228 draw_cfg_node (pp, funcdef_no, bb); | |
229 } | |
230 | |
231 free (body); | |
232 | |
233 if (loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun)) | |
234 pp_printf (pp, "\t}\n"); | |
235 } | |
236 | |
237 /* Draw all the basic blocks in the CFG in case the loop tree is available. | |
238 All loop bodys are printed in clusters. */ | |
239 | |
240 static void | |
241 draw_cfg_nodes (pretty_printer *pp, struct function *fun) | |
242 { | |
243 if (loops_for_fn (fun)) | |
244 draw_cfg_nodes_for_loop (pp, fun->funcdef_no, get_loop (fun, 0)); | |
245 else | |
246 draw_cfg_nodes_no_loops (pp, fun); | |
247 } | |
248 | |
249 /* Draw all edges in the CFG. Retreating edges are drawin as not | |
250 constraining, this makes the layout of the graph better. */ | |
251 | |
252 static void | |
253 draw_cfg_edges (pretty_printer *pp, struct function *fun) | |
254 { | |
255 basic_block bb; | |
256 | |
257 /* Save EDGE_DFS_BACK flag to dfs_back. */ | |
258 auto_bitmap dfs_back; | |
259 edge e; | |
260 edge_iterator ei; | |
261 unsigned int idx = 0; | |
262 FOR_EACH_BB_FN (bb, cfun) | |
263 FOR_EACH_EDGE (e, ei, bb->succs) | |
264 { | |
265 if (e->flags & EDGE_DFS_BACK) | |
266 bitmap_set_bit (dfs_back, idx); | |
267 idx++; | |
268 } | |
269 | |
270 mark_dfs_back_edges (); | |
271 FOR_ALL_BB_FN (bb, cfun) | |
272 draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb); | |
273 | |
274 /* Restore EDGE_DFS_BACK flag from dfs_back. */ | |
275 idx = 0; | |
276 FOR_EACH_BB_FN (bb, cfun) | |
277 FOR_EACH_EDGE (e, ei, bb->succs) | |
278 { | |
279 if (bitmap_bit_p (dfs_back, idx)) | |
280 e->flags |= EDGE_DFS_BACK; | |
281 else | |
282 e->flags &= ~EDGE_DFS_BACK; | |
283 idx++; | |
284 } | |
0 | 285 |
111 | 286 /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */ |
287 pp_printf (pp, | |
288 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n " | |
289 "[style=\"invis\",constraint=true];\n", | |
290 fun->funcdef_no, ENTRY_BLOCK, | |
291 fun->funcdef_no, EXIT_BLOCK); | |
292 pp_flush (pp); | |
293 } | |
294 | |
295 /* Print a graphical representation of the CFG of function FUN. | |
296 First print all basic blocks. Draw all edges at the end to get | |
297 subgraphs right for GraphViz, which requires nodes to be defined | |
298 before edges to cluster nodes properly. */ | |
299 | |
300 void DEBUG_FUNCTION | |
301 print_graph_cfg (FILE *fp, struct function *fun) | |
302 { | |
303 pretty_printer graph_slim_pp; | |
304 graph_slim_pp.buffer->stream = fp; | |
305 pretty_printer *const pp = &graph_slim_pp; | |
306 const char *funcname = function_name (fun); | |
307 pp_printf (pp, "subgraph \"cluster_%s\" {\n" | |
308 "\tstyle=\"dashed\";\n" | |
309 "\tcolor=\"black\";\n" | |
310 "\tlabel=\"%s ()\";\n", | |
311 funcname, funcname); | |
312 draw_cfg_nodes (pp, fun); | |
313 draw_cfg_edges (pp, fun); | |
314 pp_printf (pp, "}\n"); | |
315 pp_flush (pp); | |
316 } | |
317 | |
318 /* Overload with additional flag argument. */ | |
319 | |
320 void DEBUG_FUNCTION | |
321 print_graph_cfg (FILE *fp, struct function *fun, dump_flags_t flags) | |
322 { | |
323 dump_flags_t saved_dump_flags = dump_flags; | |
324 dump_flags = flags; | |
325 print_graph_cfg (fp, fun); | |
326 dump_flags = saved_dump_flags; | |
327 } | |
328 | |
329 | |
330 /* Print a graphical representation of the CFG of function FUN. | |
331 First print all basic blocks. Draw all edges at the end to get | |
332 subgraphs right for GraphViz, which requires nodes to be defined | |
333 before edges to cluster nodes properly. */ | |
334 | |
335 void | |
336 print_graph_cfg (const char *base, struct function *fun) | |
337 { | |
338 FILE *fp = open_graph_file (base, "a"); | |
339 print_graph_cfg (fp, fun); | |
340 fclose (fp); | |
341 } | |
342 | |
343 /* Start the dump of a graph. */ | |
344 static void | |
345 start_graph_dump (FILE *fp, const char *base) | |
346 { | |
347 pretty_printer graph_slim_pp; | |
348 graph_slim_pp.buffer->stream = fp; | |
349 pretty_printer *const pp = &graph_slim_pp; | |
350 pp_string (pp, "digraph \""); | |
351 pp_write_text_to_stream (pp); | |
352 pp_string (pp, base); | |
353 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false); | |
354 pp_string (pp, "\" {\n"); | |
355 pp_string (pp, "overlap=false;\n"); | |
356 pp_flush (pp); | |
357 } | |
358 | |
359 /* End the dump of a graph. */ | |
360 static void | |
361 end_graph_dump (FILE *fp) | |
362 { | |
363 fputs ("}\n", fp); | |
364 } | |
365 | |
366 /* Similar as clean_dump_file, but this time for graph output files. */ | |
367 void | |
368 clean_graph_dump_file (const char *base) | |
369 { | |
370 FILE *fp = open_graph_file (base, "w"); | |
371 start_graph_dump (fp, base); | |
0 | 372 fclose (fp); |
373 } | |
374 | |
375 | |
376 /* Do final work on the graph output file. */ | |
377 void | |
378 finish_graph_dump_file (const char *base) | |
379 { | |
111 | 380 FILE *fp = open_graph_file (base, "a"); |
381 end_graph_dump (fp); | |
382 fclose (fp); | |
0 | 383 } |