Mercurial > hg > CbC > CbC_gcc
comparison gcc/graph.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* Output routines for graphical representation. | 1 /* Output routines for graphical representation. |
2 Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2007, 2008, 2010 | 2 Copyright (C) 1998-2017 Free Software Foundation, Inc. |
3 Free Software Foundation, Inc. | |
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. | 3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. |
4 Rewritten for DOT output by Steven Bosscher, 2012. | |
5 | 5 |
6 This file is part of GCC. | 6 This file is part of GCC. |
7 | 7 |
8 GCC is free software; you can redistribute it and/or modify it under | 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 | 9 the terms of the GNU General Public License as published by the Free |
20 <http://www.gnu.org/licenses/>. */ | 20 <http://www.gnu.org/licenses/>. */ |
21 | 21 |
22 #include "config.h" | 22 #include "config.h" |
23 #include "system.h" | 23 #include "system.h" |
24 #include "coretypes.h" | 24 #include "coretypes.h" |
25 #include "tm.h" | 25 #include "backend.h" |
26 #include "rtl.h" | 26 #include "cfghooks.h" |
27 #include "flags.h" | 27 #include "pretty-print.h" |
28 #include "output.h" | 28 #include "diagnostic-core.h" /* for fatal_error */ |
29 #include "function.h" | 29 #include "cfganal.h" |
30 #include "hard-reg-set.h" | 30 #include "cfgloop.h" |
31 #include "obstack.h" | |
32 #include "basic-block.h" | |
33 #include "diagnostic-core.h" | |
34 #include "graph.h" | 31 #include "graph.h" |
35 #include "emit-rtl.h" | 32 #include "dumpfile.h" |
36 | 33 |
37 static const char *const graph_ext[] = | 34 /* DOT files with the .dot extension are recognized as document templates |
38 { | 35 by a well-known piece of word processing software out of Redmond, WA. |
39 /* no_graph */ "", | 36 Therefore some recommend using the .gv extension instead. Obstinately |
40 /* vcg */ ".vcg", | 37 ignore that recommendation... */ |
41 }; | 38 static const char *const graph_ext = ".dot"; |
42 | 39 |
43 /* The flag to indicate if output is inside of a building block. */ | 40 /* Open a file with MODE for dumping our graph to. |
44 static int inbb = 0; | 41 Return the file pointer. */ |
45 | 42 static FILE * |
46 static void start_fct (FILE *); | 43 open_graph_file (const char *base, const char *mode) |
47 static void start_bb (FILE *, int); | 44 { |
48 static void node_data (FILE *, rtx); | |
49 static void draw_edge (FILE *, int, int, int, int); | |
50 static void end_fct (FILE *); | |
51 static void end_bb (FILE *); | |
52 | |
53 /* Output text for new basic block. */ | |
54 static void | |
55 start_fct (FILE *fp) | |
56 { | |
57 switch (graph_dump_format) | |
58 { | |
59 case vcg: | |
60 fprintf (fp, "\ | |
61 graph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n", | |
62 current_function_name (), current_function_name ()); | |
63 break; | |
64 case no_graph: | |
65 break; | |
66 } | |
67 } | |
68 | |
69 static void | |
70 start_bb (FILE *fp, int bb) | |
71 { | |
72 #if 0 | |
73 reg_set_iterator rsi; | |
74 #endif | |
75 | |
76 switch (graph_dump_format) | |
77 { | |
78 case vcg: | |
79 fprintf (fp, "\ | |
80 graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\ | |
81 label: \"basic block %d", | |
82 current_function_name (), bb, bb); | |
83 inbb = 1; /* Now We are inside of a building block. */ | |
84 break; | |
85 case no_graph: | |
86 break; | |
87 } | |
88 | |
89 #if 0 | |
90 /* FIXME Should this be printed? It makes the graph significantly larger. */ | |
91 | |
92 /* Print the live-at-start register list. */ | |
93 fputc ('\n', fp); | |
94 EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i, rsi) | |
95 { | |
96 fprintf (fp, " %d", i); | |
97 if (i < FIRST_PSEUDO_REGISTER) | |
98 fprintf (fp, " [%s]", reg_names[i]); | |
99 } | |
100 #endif | |
101 | |
102 switch (graph_dump_format) | |
103 { | |
104 case vcg: | |
105 fputs ("\"\n\n", fp); | |
106 break; | |
107 case no_graph: | |
108 break; | |
109 } | |
110 } | |
111 | |
112 static void | |
113 node_data (FILE *fp, rtx tmp_rtx) | |
114 { | |
115 if (PREV_INSN (tmp_rtx) == 0) | |
116 { | |
117 /* This is the first instruction. Add an edge from the starting | |
118 block. */ | |
119 switch (graph_dump_format) | |
120 { | |
121 case vcg: | |
122 fprintf (fp, "\ | |
123 edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n", | |
124 current_function_name (), | |
125 current_function_name (), XINT (tmp_rtx, 0)); | |
126 break; | |
127 case no_graph: | |
128 break; | |
129 } | |
130 } | |
131 | |
132 switch (graph_dump_format) | |
133 { | |
134 case vcg: | |
135 fprintf (fp, "node: {\n title: \"%s.%d\"\n color: %s\n \ | |
136 label: \"%s %d\n", | |
137 current_function_name (), XINT (tmp_rtx, 0), | |
138 NOTE_P (tmp_rtx) ? "lightgrey" | |
139 : NONJUMP_INSN_P (tmp_rtx) ? "green" | |
140 : JUMP_P (tmp_rtx) ? "darkgreen" | |
141 : CALL_P (tmp_rtx) ? "darkgreen" | |
142 : LABEL_P (tmp_rtx) ? "\ | |
143 darkgrey\n shape: ellipse" : "white", | |
144 GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0)); | |
145 break; | |
146 case no_graph: | |
147 break; | |
148 } | |
149 | |
150 /* Print the RTL. */ | |
151 if (NOTE_P (tmp_rtx)) | |
152 { | |
153 const char *name; | |
154 name = GET_NOTE_INSN_NAME (NOTE_KIND (tmp_rtx)); | |
155 fprintf (fp, " %s", name); | |
156 } | |
157 else if (INSN_P (tmp_rtx)) | |
158 print_rtl_single (fp, PATTERN (tmp_rtx)); | |
159 else | |
160 print_rtl_single (fp, tmp_rtx); | |
161 | |
162 switch (graph_dump_format) | |
163 { | |
164 case vcg: | |
165 fputs ("\"\n}\n", fp); | |
166 break; | |
167 case no_graph: | |
168 break; | |
169 } | |
170 } | |
171 | |
172 static void | |
173 draw_edge (FILE *fp, int from, int to, int bb_edge, int color_class) | |
174 { | |
175 const char * color; | |
176 switch (graph_dump_format) | |
177 { | |
178 case vcg: | |
179 color = ""; | |
180 if (color_class == 2) | |
181 color = "color: red "; | |
182 else if (bb_edge) | |
183 color = "color: blue "; | |
184 else if (color_class == 3) | |
185 color = "color: green "; | |
186 fprintf (fp, | |
187 "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s", | |
188 current_function_name (), from, | |
189 current_function_name (), to, color); | |
190 if (color_class) | |
191 fprintf (fp, "class: %d ", color_class); | |
192 fputs ("}\n", fp); | |
193 break; | |
194 case no_graph: | |
195 break; | |
196 } | |
197 } | |
198 | |
199 static void | |
200 end_bb (FILE *fp) | |
201 { | |
202 switch (graph_dump_format) | |
203 { | |
204 case vcg: | |
205 /* Check if we are inside of a building block. */ | |
206 if (inbb != 0) | |
207 { | |
208 fputs ("}\n", fp); | |
209 inbb = 0; /* Now we are outside of a building block. */ | |
210 } | |
211 break; | |
212 case no_graph: | |
213 break; | |
214 } | |
215 } | |
216 | |
217 static void | |
218 end_fct (FILE *fp) | |
219 { | |
220 switch (graph_dump_format) | |
221 { | |
222 case vcg: | |
223 fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n", | |
224 current_function_name ()); | |
225 break; | |
226 case no_graph: | |
227 break; | |
228 } | |
229 } | |
230 | |
231 /* Like print_rtl, but also print out live information for the start of each | |
232 basic block. */ | |
233 void | |
234 print_rtl_graph_with_bb (const char *base, rtx rtx_first) | |
235 { | |
236 rtx tmp_rtx; | |
237 size_t namelen = strlen (base); | 45 size_t namelen = strlen (base); |
238 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; | 46 size_t extlen = strlen (graph_ext) + 1; |
239 char *buf = XALLOCAVEC (char, namelen + extlen); | 47 char *buf = XALLOCAVEC (char, namelen + extlen); |
240 FILE *fp; | 48 FILE *fp; |
241 | 49 |
242 if (basic_block_info == NULL) | 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", | |
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); | |
212 | |
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) | |
243 return; | 217 return; |
244 | 218 |
245 memcpy (buf, base, namelen); | 219 if (loop->latch == EXIT_BLOCK_PTR_FOR_FN (cfun)) |
246 memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); | 220 body = get_loop_body (loop); |
247 | |
248 fp = fopen (buf, "a"); | |
249 if (fp == NULL) | |
250 return; | |
251 | |
252 if (rtx_first == 0) | |
253 fprintf (fp, "(nil)\n"); | |
254 else | 221 else |
255 { | 222 body = get_loop_body_in_bfs_order (loop); |
256 enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB }; | 223 |
257 int max_uid = get_max_uid (); | 224 for (i = 0; i < loop->num_nodes; i++) |
258 int *start = XNEWVEC (int, max_uid); | 225 { |
259 int *end = XNEWVEC (int, max_uid); | 226 basic_block bb = body[i]; |
260 enum bb_state *in_bb_p = XNEWVEC (enum bb_state, max_uid); | 227 if (bb->loop_father == loop) |
261 basic_block bb; | 228 draw_cfg_node (pp, funcdef_no, bb); |
262 int i; | 229 } |
263 | 230 |
264 for (i = 0; i < max_uid; ++i) | 231 free (body); |
265 { | 232 |
266 start[i] = end[i] = -1; | 233 if (loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun)) |
267 in_bb_p[i] = NOT_IN_BB; | 234 pp_printf (pp, "\t}\n"); |
268 } | 235 } |
269 | 236 |
270 FOR_EACH_BB_REVERSE (bb) | 237 /* Draw all the basic blocks in the CFG in case the loop tree is available. |
271 { | 238 All loop bodys are printed in clusters. */ |
272 rtx x; | 239 |
273 start[INSN_UID (BB_HEAD (bb))] = bb->index; | 240 static void |
274 end[INSN_UID (BB_END (bb))] = bb->index; | 241 draw_cfg_nodes (pretty_printer *pp, struct function *fun) |
275 for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x)) | 242 { |
276 { | 243 if (loops_for_fn (fun)) |
277 in_bb_p[INSN_UID (x)] | 244 draw_cfg_nodes_for_loop (pp, fun->funcdef_no, get_loop (fun, 0)); |
278 = (in_bb_p[INSN_UID (x)] == NOT_IN_BB) | 245 else |
279 ? IN_ONE_BB : IN_MULTIPLE_BB; | 246 draw_cfg_nodes_no_loops (pp, fun); |
280 if (x == BB_END (bb)) | 247 } |
281 break; | 248 |
282 } | 249 /* Draw all edges in the CFG. Retreating edges are drawin as not |
283 } | 250 constraining, this makes the layout of the graph better. */ |
284 | 251 |
285 /* Tell print-rtl that we want graph output. */ | 252 static void |
286 dump_for_graph = 1; | 253 draw_cfg_edges (pretty_printer *pp, struct function *fun) |
287 | 254 { |
288 /* Start new function. */ | 255 basic_block bb; |
289 start_fct (fp); | 256 |
290 | 257 /* Save EDGE_DFS_BACK flag to dfs_back. */ |
291 for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx; | 258 auto_bitmap dfs_back; |
292 tmp_rtx = NEXT_INSN (tmp_rtx)) | 259 edge e; |
293 { | 260 edge_iterator ei; |
294 int edge_printed = 0; | 261 unsigned int idx = 0; |
295 rtx next_insn; | 262 FOR_EACH_BB_FN (bb, cfun) |
296 | 263 FOR_EACH_EDGE (e, ei, bb->succs) |
297 if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0) | 264 { |
298 { | 265 if (e->flags & EDGE_DFS_BACK) |
299 if (BARRIER_P (tmp_rtx)) | 266 bitmap_set_bit (dfs_back, idx); |
300 continue; | 267 idx++; |
301 if (NOTE_P (tmp_rtx) | 268 } |
302 && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB)) | 269 |
303 continue; | 270 mark_dfs_back_edges (); |
304 } | 271 FOR_ALL_BB_FN (bb, cfun) |
305 | 272 draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb); |
306 if ((i = start[INSN_UID (tmp_rtx)]) >= 0) | 273 |
307 { | 274 /* Restore EDGE_DFS_BACK flag from dfs_back. */ |
308 /* We start a subgraph for each basic block. */ | 275 idx = 0; |
309 start_bb (fp, i); | 276 FOR_EACH_BB_FN (bb, cfun) |
310 | 277 FOR_EACH_EDGE (e, ei, bb->succs) |
311 if (i == 0) | 278 { |
312 draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0); | 279 if (bitmap_bit_p (dfs_back, idx)) |
313 } | 280 e->flags |= EDGE_DFS_BACK; |
314 | 281 else |
315 /* Print the data for this node. */ | 282 e->flags &= ~EDGE_DFS_BACK; |
316 node_data (fp, tmp_rtx); | 283 idx++; |
317 next_insn = next_nonnote_insn (tmp_rtx); | 284 } |
318 | 285 |
319 if ((i = end[INSN_UID (tmp_rtx)]) >= 0) | 286 /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */ |
320 { | 287 pp_printf (pp, |
321 edge e; | 288 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n " |
322 edge_iterator ei; | 289 "[style=\"invis\",constraint=true];\n", |
323 | 290 fun->funcdef_no, ENTRY_BLOCK, |
324 bb = BASIC_BLOCK (i); | 291 fun->funcdef_no, EXIT_BLOCK); |
325 | 292 pp_flush (pp); |
326 /* End of the basic block. */ | 293 } |
327 end_bb (fp); | 294 |
328 | 295 /* Print a graphical representation of the CFG of function FUN. |
329 /* Now specify the edges to all the successors of this | 296 First print all basic blocks. Draw all edges at the end to get |
330 basic block. */ | 297 subgraphs right for GraphViz, which requires nodes to be defined |
331 FOR_EACH_EDGE (e, ei, bb->succs) | 298 before edges to cluster nodes properly. */ |
332 { | 299 |
333 if (e->dest != EXIT_BLOCK_PTR) | 300 void DEBUG_FUNCTION |
334 { | 301 print_graph_cfg (FILE *fp, struct function *fun) |
335 rtx block_head = BB_HEAD (e->dest); | 302 { |
336 | 303 pretty_printer graph_slim_pp; |
337 draw_edge (fp, INSN_UID (tmp_rtx), | 304 graph_slim_pp.buffer->stream = fp; |
338 INSN_UID (block_head), | 305 pretty_printer *const pp = &graph_slim_pp; |
339 next_insn != block_head, | 306 const char *funcname = function_name (fun); |
340 (e->flags & EDGE_ABNORMAL ? 2 : 0)); | 307 pp_printf (pp, "subgraph \"cluster_%s\" {\n" |
341 | 308 "\tstyle=\"dashed\";\n" |
342 if (block_head == next_insn) | 309 "\tcolor=\"black\";\n" |
343 edge_printed = 1; | 310 "\tlabel=\"%s ()\";\n", |
344 } | 311 funcname, funcname); |
345 else | 312 draw_cfg_nodes (pp, fun); |
346 { | 313 draw_cfg_edges (pp, fun); |
347 draw_edge (fp, INSN_UID (tmp_rtx), 999999, | 314 pp_printf (pp, "}\n"); |
348 next_insn != 0, | 315 pp_flush (pp); |
349 (e->flags & EDGE_ABNORMAL ? 2 : 0)); | 316 } |
350 | 317 |
351 if (next_insn == 0) | 318 /* Overload with additional flag argument. */ |
352 edge_printed = 1; | 319 |
353 } | 320 void DEBUG_FUNCTION |
354 } | 321 print_graph_cfg (FILE *fp, struct function *fun, dump_flags_t flags) |
355 } | 322 { |
356 | 323 dump_flags_t saved_dump_flags = dump_flags; |
357 if (!edge_printed) | 324 dump_flags = flags; |
358 { | 325 print_graph_cfg (fp, fun); |
359 /* Don't print edges to barriers. */ | 326 dump_flags = saved_dump_flags; |
360 if (next_insn == 0 | 327 } |
361 || !BARRIER_P (next_insn)) | 328 |
362 draw_edge (fp, XINT (tmp_rtx, 0), | 329 |
363 next_insn ? INSN_UID (next_insn) : 999999, 0, 0); | 330 /* Print a graphical representation of the CFG of function FUN. |
364 else | 331 First print all basic blocks. Draw all edges at the end to get |
365 { | 332 subgraphs right for GraphViz, which requires nodes to be defined |
366 /* We draw the remaining edges in class 3. We have | 333 before edges to cluster nodes properly. */ |
367 to skip over the barrier since these nodes are | 334 |
368 not printed at all. */ | 335 void |
369 do | 336 print_graph_cfg (const char *base, struct function *fun) |
370 next_insn = NEXT_INSN (next_insn); | 337 { |
371 while (next_insn | 338 FILE *fp = open_graph_file (base, "a"); |
372 && (NOTE_P (next_insn) | 339 print_graph_cfg (fp, fun); |
373 || BARRIER_P (next_insn))); | |
374 | |
375 draw_edge (fp, XINT (tmp_rtx, 0), | |
376 next_insn ? INSN_UID (next_insn) : 999999, 0, 3); | |
377 } | |
378 } | |
379 } | |
380 | |
381 dump_for_graph = 0; | |
382 | |
383 end_fct (fp); | |
384 | |
385 /* Clean up. */ | |
386 free (start); | |
387 free (end); | |
388 free (in_bb_p); | |
389 } | |
390 | |
391 fclose (fp); | 340 fclose (fp); |
392 } | 341 } |
393 | 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 } | |
394 | 365 |
395 /* Similar as clean_dump_file, but this time for graph output files. */ | 366 /* Similar as clean_dump_file, but this time for graph output files. */ |
396 | |
397 void | 367 void |
398 clean_graph_dump_file (const char *base) | 368 clean_graph_dump_file (const char *base) |
399 { | 369 { |
400 size_t namelen = strlen (base); | 370 FILE *fp = open_graph_file (base, "w"); |
401 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; | 371 start_graph_dump (fp, base); |
402 char *buf = XALLOCAVEC (char, namelen + extlen); | |
403 FILE *fp; | |
404 | |
405 memcpy (buf, base, namelen); | |
406 memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); | |
407 | |
408 fp = fopen (buf, "w"); | |
409 | |
410 if (fp == NULL) | |
411 fatal_error ("can%'t open %s: %m", buf); | |
412 | |
413 gcc_assert (graph_dump_format == vcg); | |
414 fputs ("graph: {\nport_sharing: no\n", fp); | |
415 | |
416 fclose (fp); | 372 fclose (fp); |
417 } | 373 } |
418 | 374 |
419 | 375 |
420 /* Do final work on the graph output file. */ | 376 /* Do final work on the graph output file. */ |
421 void | 377 void |
422 finish_graph_dump_file (const char *base) | 378 finish_graph_dump_file (const char *base) |
423 { | 379 { |
424 size_t namelen = strlen (base); | 380 FILE *fp = open_graph_file (base, "a"); |
425 size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; | 381 end_graph_dump (fp); |
426 char *buf = XALLOCAVEC (char, namelen + extlen); | 382 fclose (fp); |
427 FILE *fp; | 383 } |
428 | |
429 memcpy (buf, base, namelen); | |
430 memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); | |
431 | |
432 fp = fopen (buf, "a"); | |
433 if (fp != NULL) | |
434 { | |
435 gcc_assert (graph_dump_format == vcg); | |
436 fputs ("}\n", fp); | |
437 fclose (fp); | |
438 } | |
439 } |