]>
Commit | Line | Data |
---|---|---|
735a0e33 | 1 | /* Output routines for graphical representation. |
d8a07487 | 2 | Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2007, 2008, 2010 |
d9221e01 | 3 | Free Software Foundation, Inc. |
735a0e33 UD |
4 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. |
5 | ||
1322177d | 6 | This file is part of GCC. |
735a0e33 | 7 | |
1322177d LB |
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 | |
9dcd6f09 | 10 | Software Foundation; either version 3, or (at your option) any later |
1322177d | 11 | version. |
735a0e33 | 12 | |
1322177d LB |
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. | |
735a0e33 | 17 | |
400500c4 | 18 | You should have received a copy of the GNU General Public License |
9dcd6f09 NC |
19 | along with GCC; see the file COPYING3. If not see |
20 | <http://www.gnu.org/licenses/>. */ | |
735a0e33 UD |
21 | |
22 | #include <config.h> | |
23 | #include "system.h" | |
4977bab6 ZW |
24 | #include "coretypes.h" |
25 | #include "tm.h" | |
735a0e33 UD |
26 | #include "rtl.h" |
27 | #include "flags.h" | |
28 | #include "output.h" | |
49ad7cfa | 29 | #include "function.h" |
735a0e33 | 30 | #include "hard-reg-set.h" |
7932a3db | 31 | #include "obstack.h" |
735a0e33 | 32 | #include "basic-block.h" |
718f9c0f | 33 | #include "diagnostic-core.h" |
6a2cc2ac | 34 | #include "graph.h" |
5936d944 | 35 | #include "emit-rtl.h" |
735a0e33 | 36 | |
27c38fbe | 37 | static const char *const graph_ext[] = |
735a0e33 UD |
38 | { |
39 | /* no_graph */ "", | |
40 | /* vcg */ ".vcg", | |
41 | }; | |
42 | ||
208d8b55 TWL |
43 | /* The flag to indicate if output is inside of a building block. */ |
44 | static int inbb = 0; | |
45 | ||
1d088dee AJ |
46 | static void start_fct (FILE *); |
47 | static void start_bb (FILE *, int); | |
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 *); | |
5f06c983 | 52 | |
735a0e33 UD |
53 | /* Output text for new basic block. */ |
54 | static void | |
1d088dee | 55 | start_fct (FILE *fp) |
735a0e33 | 56 | { |
735a0e33 UD |
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", | |
faed5cc3 | 62 | current_function_name (), current_function_name ()); |
735a0e33 UD |
63 | break; |
64 | case no_graph: | |
65 | break; | |
66 | } | |
67 | } | |
68 | ||
69 | static void | |
1d088dee | 70 | start_bb (FILE *fp, int bb) |
735a0e33 | 71 | { |
a2041967 KH |
72 | #if 0 |
73 | reg_set_iterator rsi; | |
74 | #endif | |
75 | ||
735a0e33 UD |
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", | |
faed5cc3 | 82 | current_function_name (), bb, bb); |
208d8b55 | 83 | inbb = 1; /* Now We are inside of a building block. */ |
735a0e33 UD |
84 | break; |
85 | case no_graph: | |
86 | break; | |
87 | } | |
88 | ||
89 | #if 0 | |
dc297297 | 90 | /* FIXME Should this be printed? It makes the graph significantly larger. */ |
735a0e33 UD |
91 | |
92 | /* Print the live-at-start register list. */ | |
93 | fputc ('\n', fp); | |
a2041967 KH |
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 | } | |
735a0e33 UD |
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 | ||
a30d557c | 112 | static void |
1d088dee | 113 | node_data (FILE *fp, rtx tmp_rtx) |
735a0e33 | 114 | { |
735a0e33 UD |
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", | |
faed5cc3 SB |
124 | current_function_name (), |
125 | current_function_name (), XINT (tmp_rtx, 0)); | |
735a0e33 UD |
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", | |
faed5cc3 | 137 | current_function_name (), XINT (tmp_rtx, 0), |
4b4bf941 JQ |
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) ? "\ | |
735a0e33 UD |
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. */ | |
4b4bf941 | 151 | if (NOTE_P (tmp_rtx)) |
735a0e33 | 152 | { |
a38e7aa5 JH |
153 | const char *name; |
154 | name = GET_NOTE_INSN_NAME (NOTE_KIND (tmp_rtx)); | |
0a2287bf | 155 | fprintf (fp, " %s", name); |
735a0e33 | 156 | } |
2c3c49de | 157 | else if (INSN_P (tmp_rtx)) |
a30d557c | 158 | print_rtl_single (fp, PATTERN (tmp_rtx)); |
735a0e33 | 159 | else |
a30d557c | 160 | print_rtl_single (fp, tmp_rtx); |
735a0e33 UD |
161 | |
162 | switch (graph_dump_format) | |
163 | { | |
164 | case vcg: | |
165 | fputs ("\"\n}\n", fp); | |
166 | break; | |
167 | case no_graph: | |
168 | break; | |
169 | } | |
735a0e33 UD |
170 | } |
171 | ||
172 | static void | |
d858f359 | 173 | draw_edge (FILE *fp, int from, int to, int bb_edge, int color_class) |
735a0e33 | 174 | { |
5f06c983 | 175 | const char * color; |
735a0e33 UD |
176 | switch (graph_dump_format) |
177 | { | |
178 | case vcg: | |
e881bb1b | 179 | color = ""; |
d858f359 | 180 | if (color_class == 2) |
e881bb1b RH |
181 | color = "color: red "; |
182 | else if (bb_edge) | |
183 | color = "color: blue "; | |
d858f359 | 184 | else if (color_class == 3) |
e881bb1b | 185 | color = "color: green "; |
735a0e33 UD |
186 | fprintf (fp, |
187 | "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s", | |
faed5cc3 SB |
188 | current_function_name (), from, |
189 | current_function_name (), to, color); | |
d858f359 KG |
190 | if (color_class) |
191 | fprintf (fp, "class: %d ", color_class); | |
735a0e33 UD |
192 | fputs ("}\n", fp); |
193 | break; | |
194 | case no_graph: | |
195 | break; | |
196 | } | |
197 | } | |
198 | ||
199 | static void | |
1d088dee | 200 | end_bb (FILE *fp) |
735a0e33 UD |
201 | { |
202 | switch (graph_dump_format) | |
203 | { | |
204 | case vcg: | |
208d8b55 TWL |
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 | } | |
735a0e33 UD |
211 | break; |
212 | case no_graph: | |
213 | break; | |
214 | } | |
215 | } | |
216 | ||
217 | static void | |
1d088dee | 218 | end_fct (FILE *fp) |
735a0e33 UD |
219 | { |
220 | switch (graph_dump_format) | |
221 | { | |
222 | case vcg: | |
223 | fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n", | |
faed5cc3 | 224 | current_function_name ()); |
735a0e33 UD |
225 | break; |
226 | case no_graph: | |
227 | break; | |
228 | } | |
229 | } | |
230 | \f | |
231 | /* Like print_rtl, but also print out live information for the start of each | |
232 | basic block. */ | |
233 | void | |
9f8628ba | 234 | print_rtl_graph_with_bb (const char *base, rtx rtx_first) |
735a0e33 | 235 | { |
b3694847 | 236 | rtx tmp_rtx; |
735a0e33 | 237 | size_t namelen = strlen (base); |
735a0e33 | 238 | size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; |
d3bfe4de | 239 | char *buf = XALLOCAVEC (char, namelen + extlen); |
735a0e33 UD |
240 | FILE *fp; |
241 | ||
e881bb1b RH |
242 | if (basic_block_info == NULL) |
243 | return; | |
735a0e33 UD |
244 | |
245 | memcpy (buf, base, namelen); | |
9f8628ba | 246 | memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); |
735a0e33 UD |
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 | |
255 | { | |
735a0e33 UD |
256 | enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB }; |
257 | int max_uid = get_max_uid (); | |
5ed6ace5 MD |
258 | int *start = XNEWVEC (int, max_uid); |
259 | int *end = XNEWVEC (int, max_uid); | |
260 | enum bb_state *in_bb_p = XNEWVEC (enum bb_state, max_uid); | |
e881bb1b | 261 | basic_block bb; |
e0082a72 | 262 | int i; |
735a0e33 | 263 | |
0b17ab2f | 264 | for (i = 0; i < max_uid; ++i) |
735a0e33 | 265 | { |
0b17ab2f RH |
266 | start[i] = end[i] = -1; |
267 | in_bb_p[i] = NOT_IN_BB; | |
735a0e33 UD |
268 | } |
269 | ||
e0082a72 | 270 | FOR_EACH_BB_REVERSE (bb) |
735a0e33 UD |
271 | { |
272 | rtx x; | |
a813c111 SB |
273 | start[INSN_UID (BB_HEAD (bb))] = bb->index; |
274 | end[INSN_UID (BB_END (bb))] = bb->index; | |
275 | for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x)) | |
735a0e33 UD |
276 | { |
277 | in_bb_p[INSN_UID (x)] | |
278 | = (in_bb_p[INSN_UID (x)] == NOT_IN_BB) | |
279 | ? IN_ONE_BB : IN_MULTIPLE_BB; | |
a813c111 | 280 | if (x == BB_END (bb)) |
735a0e33 UD |
281 | break; |
282 | } | |
283 | } | |
284 | ||
735a0e33 UD |
285 | /* Tell print-rtl that we want graph output. */ |
286 | dump_for_graph = 1; | |
287 | ||
288 | /* Start new function. */ | |
289 | start_fct (fp); | |
290 | ||
291 | for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx; | |
292 | tmp_rtx = NEXT_INSN (tmp_rtx)) | |
293 | { | |
735a0e33 UD |
294 | int edge_printed = 0; |
295 | rtx next_insn; | |
296 | ||
297 | if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0) | |
298 | { | |
4b4bf941 | 299 | if (BARRIER_P (tmp_rtx)) |
735a0e33 | 300 | continue; |
4b4bf941 | 301 | if (NOTE_P (tmp_rtx) |
735a0e33 UD |
302 | && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB)) |
303 | continue; | |
304 | } | |
305 | ||
0b17ab2f | 306 | if ((i = start[INSN_UID (tmp_rtx)]) >= 0) |
735a0e33 UD |
307 | { |
308 | /* We start a subgraph for each basic block. */ | |
0b17ab2f | 309 | start_bb (fp, i); |
735a0e33 | 310 | |
0b17ab2f | 311 | if (i == 0) |
735a0e33 UD |
312 | draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0); |
313 | } | |
314 | ||
315 | /* Print the data for this node. */ | |
a30d557c | 316 | node_data (fp, tmp_rtx); |
735a0e33 UD |
317 | next_insn = next_nonnote_insn (tmp_rtx); |
318 | ||
0b17ab2f | 319 | if ((i = end[INSN_UID (tmp_rtx)]) >= 0) |
735a0e33 | 320 | { |
e881bb1b | 321 | edge e; |
628f6a4e | 322 | edge_iterator ei; |
e881bb1b | 323 | |
0b17ab2f | 324 | bb = BASIC_BLOCK (i); |
735a0e33 UD |
325 | |
326 | /* End of the basic block. */ | |
5f06c983 | 327 | end_bb (fp); |
735a0e33 UD |
328 | |
329 | /* Now specify the edges to all the successors of this | |
330 | basic block. */ | |
628f6a4e | 331 | FOR_EACH_EDGE (e, ei, bb->succs) |
735a0e33 | 332 | { |
e881bb1b | 333 | if (e->dest != EXIT_BLOCK_PTR) |
735a0e33 | 334 | { |
a813c111 | 335 | rtx block_head = BB_HEAD (e->dest); |
735a0e33 UD |
336 | |
337 | draw_edge (fp, INSN_UID (tmp_rtx), | |
338 | INSN_UID (block_head), | |
e881bb1b RH |
339 | next_insn != block_head, |
340 | (e->flags & EDGE_ABNORMAL ? 2 : 0)); | |
735a0e33 | 341 | |
e881bb1b | 342 | if (block_head == next_insn) |
735a0e33 UD |
343 | edge_printed = 1; |
344 | } | |
e881bb1b | 345 | else |
735a0e33 UD |
346 | { |
347 | draw_edge (fp, INSN_UID (tmp_rtx), 999999, | |
e881bb1b RH |
348 | next_insn != 0, |
349 | (e->flags & EDGE_ABNORMAL ? 2 : 0)); | |
735a0e33 UD |
350 | |
351 | if (next_insn == 0) | |
352 | edge_printed = 1; | |
353 | } | |
735a0e33 UD |
354 | } |
355 | } | |
356 | ||
357 | if (!edge_printed) | |
358 | { | |
359 | /* Don't print edges to barriers. */ | |
360 | if (next_insn == 0 | |
4b4bf941 | 361 | || !BARRIER_P (next_insn)) |
735a0e33 UD |
362 | draw_edge (fp, XINT (tmp_rtx, 0), |
363 | next_insn ? INSN_UID (next_insn) : 999999, 0, 0); | |
364 | else | |
365 | { | |
e881bb1b RH |
366 | /* We draw the remaining edges in class 3. We have |
367 | to skip over the barrier since these nodes are | |
735a0e33 UD |
368 | not printed at all. */ |
369 | do | |
370 | next_insn = NEXT_INSN (next_insn); | |
371 | while (next_insn | |
4b4bf941 JQ |
372 | && (NOTE_P (next_insn) |
373 | || BARRIER_P (next_insn))); | |
735a0e33 UD |
374 | |
375 | draw_edge (fp, XINT (tmp_rtx, 0), | |
e881bb1b | 376 | next_insn ? INSN_UID (next_insn) : 999999, 0, 3); |
735a0e33 UD |
377 | } |
378 | } | |
379 | } | |
380 | ||
381 | dump_for_graph = 0; | |
382 | ||
383 | end_fct (fp); | |
4da896b2 MM |
384 | |
385 | /* Clean up. */ | |
386 | free (start); | |
387 | free (end); | |
388 | free (in_bb_p); | |
735a0e33 UD |
389 | } |
390 | ||
391 | fclose (fp); | |
392 | } | |
393 | ||
394 | ||
395 | /* Similar as clean_dump_file, but this time for graph output files. */ | |
400500c4 | 396 | |
735a0e33 | 397 | void |
9f8628ba | 398 | clean_graph_dump_file (const char *base) |
735a0e33 UD |
399 | { |
400 | size_t namelen = strlen (base); | |
735a0e33 | 401 | size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; |
d3bfe4de | 402 | char *buf = XALLOCAVEC (char, namelen + extlen); |
735a0e33 UD |
403 | FILE *fp; |
404 | ||
405 | memcpy (buf, base, namelen); | |
9f8628ba | 406 | memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); |
735a0e33 UD |
407 | |
408 | fp = fopen (buf, "w"); | |
409 | ||
410 | if (fp == NULL) | |
d8a07487 | 411 | fatal_error ("can%'t open %s: %m", buf); |
735a0e33 | 412 | |
282899df NS |
413 | gcc_assert (graph_dump_format == vcg); |
414 | fputs ("graph: {\nport_sharing: no\n", fp); | |
735a0e33 UD |
415 | |
416 | fclose (fp); | |
417 | } | |
418 | ||
419 | ||
420 | /* Do final work on the graph output file. */ | |
421 | void | |
9f8628ba | 422 | finish_graph_dump_file (const char *base) |
735a0e33 UD |
423 | { |
424 | size_t namelen = strlen (base); | |
735a0e33 | 425 | size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; |
d3bfe4de | 426 | char *buf = XALLOCAVEC (char, namelen + extlen); |
735a0e33 UD |
427 | FILE *fp; |
428 | ||
429 | memcpy (buf, base, namelen); | |
9f8628ba | 430 | memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); |
735a0e33 UD |
431 | |
432 | fp = fopen (buf, "a"); | |
433 | if (fp != NULL) | |
434 | { | |
282899df NS |
435 | gcc_assert (graph_dump_format == vcg); |
436 | fputs ("}\n", fp); | |
735a0e33 UD |
437 | fclose (fp); |
438 | } | |
439 | } |