]>
Commit | Line | Data |
---|---|---|
735a0e33 | 1 | /* Output routines for graphical representation. |
9dcd6f09 | 2 | Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2007 |
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 UD |
32 | #include "basic-block.h" |
33 | #include "toplev.h" | |
6a2cc2ac | 34 | #include "graph.h" |
735a0e33 | 35 | |
27c38fbe | 36 | static const char *const graph_ext[] = |
735a0e33 UD |
37 | { |
38 | /* no_graph */ "", | |
39 | /* vcg */ ".vcg", | |
40 | }; | |
41 | ||
1d088dee AJ |
42 | static void start_fct (FILE *); |
43 | static void start_bb (FILE *, int); | |
44 | static void node_data (FILE *, rtx); | |
45 | static void draw_edge (FILE *, int, int, int, int); | |
46 | static void end_fct (FILE *); | |
47 | static void end_bb (FILE *); | |
5f06c983 | 48 | |
735a0e33 UD |
49 | /* Output text for new basic block. */ |
50 | static void | |
1d088dee | 51 | start_fct (FILE *fp) |
735a0e33 | 52 | { |
735a0e33 UD |
53 | switch (graph_dump_format) |
54 | { | |
55 | case vcg: | |
56 | fprintf (fp, "\ | |
57 | graph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n", | |
faed5cc3 | 58 | current_function_name (), current_function_name ()); |
735a0e33 UD |
59 | break; |
60 | case no_graph: | |
61 | break; | |
62 | } | |
63 | } | |
64 | ||
65 | static void | |
1d088dee | 66 | start_bb (FILE *fp, int bb) |
735a0e33 | 67 | { |
a2041967 KH |
68 | #if 0 |
69 | reg_set_iterator rsi; | |
70 | #endif | |
71 | ||
735a0e33 UD |
72 | switch (graph_dump_format) |
73 | { | |
74 | case vcg: | |
75 | fprintf (fp, "\ | |
76 | graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\ | |
77 | label: \"basic block %d", | |
faed5cc3 | 78 | current_function_name (), bb, bb); |
735a0e33 UD |
79 | break; |
80 | case no_graph: | |
81 | break; | |
82 | } | |
83 | ||
84 | #if 0 | |
dc297297 | 85 | /* FIXME Should this be printed? It makes the graph significantly larger. */ |
735a0e33 UD |
86 | |
87 | /* Print the live-at-start register list. */ | |
88 | fputc ('\n', fp); | |
a2041967 KH |
89 | EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i, rsi) |
90 | { | |
91 | fprintf (fp, " %d", i); | |
92 | if (i < FIRST_PSEUDO_REGISTER) | |
93 | fprintf (fp, " [%s]", reg_names[i]); | |
94 | } | |
735a0e33 UD |
95 | #endif |
96 | ||
97 | switch (graph_dump_format) | |
98 | { | |
99 | case vcg: | |
100 | fputs ("\"\n\n", fp); | |
101 | break; | |
102 | case no_graph: | |
103 | break; | |
104 | } | |
105 | } | |
106 | ||
a30d557c | 107 | static void |
1d088dee | 108 | node_data (FILE *fp, rtx tmp_rtx) |
735a0e33 | 109 | { |
735a0e33 UD |
110 | if (PREV_INSN (tmp_rtx) == 0) |
111 | { | |
112 | /* This is the first instruction. Add an edge from the starting | |
113 | block. */ | |
114 | switch (graph_dump_format) | |
115 | { | |
116 | case vcg: | |
117 | fprintf (fp, "\ | |
118 | edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n", | |
faed5cc3 SB |
119 | current_function_name (), |
120 | current_function_name (), XINT (tmp_rtx, 0)); | |
735a0e33 UD |
121 | break; |
122 | case no_graph: | |
123 | break; | |
124 | } | |
125 | } | |
126 | ||
127 | switch (graph_dump_format) | |
128 | { | |
129 | case vcg: | |
130 | fprintf (fp, "node: {\n title: \"%s.%d\"\n color: %s\n \ | |
131 | label: \"%s %d\n", | |
faed5cc3 | 132 | current_function_name (), XINT (tmp_rtx, 0), |
4b4bf941 JQ |
133 | NOTE_P (tmp_rtx) ? "lightgrey" |
134 | : NONJUMP_INSN_P (tmp_rtx) ? "green" | |
135 | : JUMP_P (tmp_rtx) ? "darkgreen" | |
136 | : CALL_P (tmp_rtx) ? "darkgreen" | |
137 | : LABEL_P (tmp_rtx) ? "\ | |
735a0e33 UD |
138 | darkgrey\n shape: ellipse" : "white", |
139 | GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0)); | |
140 | break; | |
141 | case no_graph: | |
142 | break; | |
143 | } | |
144 | ||
145 | /* Print the RTL. */ | |
4b4bf941 | 146 | if (NOTE_P (tmp_rtx)) |
735a0e33 | 147 | { |
a38e7aa5 JH |
148 | const char *name; |
149 | name = GET_NOTE_INSN_NAME (NOTE_KIND (tmp_rtx)); | |
0a2287bf | 150 | fprintf (fp, " %s", name); |
735a0e33 | 151 | } |
2c3c49de | 152 | else if (INSN_P (tmp_rtx)) |
a30d557c | 153 | print_rtl_single (fp, PATTERN (tmp_rtx)); |
735a0e33 | 154 | else |
a30d557c | 155 | print_rtl_single (fp, tmp_rtx); |
735a0e33 UD |
156 | |
157 | switch (graph_dump_format) | |
158 | { | |
159 | case vcg: | |
160 | fputs ("\"\n}\n", fp); | |
161 | break; | |
162 | case no_graph: | |
163 | break; | |
164 | } | |
735a0e33 UD |
165 | } |
166 | ||
167 | static void | |
1d088dee | 168 | draw_edge (FILE *fp, int from, int to, int bb_edge, int class) |
735a0e33 | 169 | { |
5f06c983 | 170 | const char * color; |
735a0e33 UD |
171 | switch (graph_dump_format) |
172 | { | |
173 | case vcg: | |
e881bb1b RH |
174 | color = ""; |
175 | if (class == 2) | |
176 | color = "color: red "; | |
177 | else if (bb_edge) | |
178 | color = "color: blue "; | |
179 | else if (class == 3) | |
180 | color = "color: green "; | |
735a0e33 UD |
181 | fprintf (fp, |
182 | "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s", | |
faed5cc3 SB |
183 | current_function_name (), from, |
184 | current_function_name (), to, color); | |
735a0e33 UD |
185 | if (class) |
186 | fprintf (fp, "class: %d ", class); | |
187 | fputs ("}\n", fp); | |
188 | break; | |
189 | case no_graph: | |
190 | break; | |
191 | } | |
192 | } | |
193 | ||
194 | static void | |
1d088dee | 195 | end_bb (FILE *fp) |
735a0e33 UD |
196 | { |
197 | switch (graph_dump_format) | |
198 | { | |
199 | case vcg: | |
200 | fputs ("}\n", fp); | |
201 | break; | |
202 | case no_graph: | |
203 | break; | |
204 | } | |
205 | } | |
206 | ||
207 | static void | |
1d088dee | 208 | end_fct (FILE *fp) |
735a0e33 UD |
209 | { |
210 | switch (graph_dump_format) | |
211 | { | |
212 | case vcg: | |
213 | fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n", | |
faed5cc3 | 214 | current_function_name ()); |
735a0e33 UD |
215 | break; |
216 | case no_graph: | |
217 | break; | |
218 | } | |
219 | } | |
220 | \f | |
221 | /* Like print_rtl, but also print out live information for the start of each | |
222 | basic block. */ | |
223 | void | |
9f8628ba | 224 | print_rtl_graph_with_bb (const char *base, rtx rtx_first) |
735a0e33 | 225 | { |
b3694847 | 226 | rtx tmp_rtx; |
735a0e33 | 227 | size_t namelen = strlen (base); |
735a0e33 | 228 | size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; |
9f8628ba | 229 | char *buf = alloca (namelen + extlen); |
735a0e33 UD |
230 | FILE *fp; |
231 | ||
e881bb1b RH |
232 | if (basic_block_info == NULL) |
233 | return; | |
735a0e33 UD |
234 | |
235 | memcpy (buf, base, namelen); | |
9f8628ba | 236 | memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); |
735a0e33 UD |
237 | |
238 | fp = fopen (buf, "a"); | |
239 | if (fp == NULL) | |
240 | return; | |
241 | ||
242 | if (rtx_first == 0) | |
243 | fprintf (fp, "(nil)\n"); | |
244 | else | |
245 | { | |
735a0e33 UD |
246 | enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB }; |
247 | int max_uid = get_max_uid (); | |
5ed6ace5 MD |
248 | int *start = XNEWVEC (int, max_uid); |
249 | int *end = XNEWVEC (int, max_uid); | |
250 | enum bb_state *in_bb_p = XNEWVEC (enum bb_state, max_uid); | |
e881bb1b | 251 | basic_block bb; |
e0082a72 | 252 | int i; |
735a0e33 | 253 | |
0b17ab2f | 254 | for (i = 0; i < max_uid; ++i) |
735a0e33 | 255 | { |
0b17ab2f RH |
256 | start[i] = end[i] = -1; |
257 | in_bb_p[i] = NOT_IN_BB; | |
735a0e33 UD |
258 | } |
259 | ||
e0082a72 | 260 | FOR_EACH_BB_REVERSE (bb) |
735a0e33 UD |
261 | { |
262 | rtx x; | |
a813c111 SB |
263 | start[INSN_UID (BB_HEAD (bb))] = bb->index; |
264 | end[INSN_UID (BB_END (bb))] = bb->index; | |
265 | for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x)) | |
735a0e33 UD |
266 | { |
267 | in_bb_p[INSN_UID (x)] | |
268 | = (in_bb_p[INSN_UID (x)] == NOT_IN_BB) | |
269 | ? IN_ONE_BB : IN_MULTIPLE_BB; | |
a813c111 | 270 | if (x == BB_END (bb)) |
735a0e33 UD |
271 | break; |
272 | } | |
273 | } | |
274 | ||
735a0e33 UD |
275 | /* Tell print-rtl that we want graph output. */ |
276 | dump_for_graph = 1; | |
277 | ||
278 | /* Start new function. */ | |
279 | start_fct (fp); | |
280 | ||
281 | for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx; | |
282 | tmp_rtx = NEXT_INSN (tmp_rtx)) | |
283 | { | |
735a0e33 UD |
284 | int edge_printed = 0; |
285 | rtx next_insn; | |
286 | ||
287 | if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0) | |
288 | { | |
4b4bf941 | 289 | if (BARRIER_P (tmp_rtx)) |
735a0e33 | 290 | continue; |
4b4bf941 | 291 | if (NOTE_P (tmp_rtx) |
735a0e33 UD |
292 | && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB)) |
293 | continue; | |
294 | } | |
295 | ||
0b17ab2f | 296 | if ((i = start[INSN_UID (tmp_rtx)]) >= 0) |
735a0e33 UD |
297 | { |
298 | /* We start a subgraph for each basic block. */ | |
0b17ab2f | 299 | start_bb (fp, i); |
735a0e33 | 300 | |
0b17ab2f | 301 | if (i == 0) |
735a0e33 UD |
302 | draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0); |
303 | } | |
304 | ||
305 | /* Print the data for this node. */ | |
a30d557c | 306 | node_data (fp, tmp_rtx); |
735a0e33 UD |
307 | next_insn = next_nonnote_insn (tmp_rtx); |
308 | ||
0b17ab2f | 309 | if ((i = end[INSN_UID (tmp_rtx)]) >= 0) |
735a0e33 | 310 | { |
e881bb1b | 311 | edge e; |
628f6a4e | 312 | edge_iterator ei; |
e881bb1b | 313 | |
0b17ab2f | 314 | bb = BASIC_BLOCK (i); |
735a0e33 UD |
315 | |
316 | /* End of the basic block. */ | |
5f06c983 | 317 | end_bb (fp); |
735a0e33 UD |
318 | |
319 | /* Now specify the edges to all the successors of this | |
320 | basic block. */ | |
628f6a4e | 321 | FOR_EACH_EDGE (e, ei, bb->succs) |
735a0e33 | 322 | { |
e881bb1b | 323 | if (e->dest != EXIT_BLOCK_PTR) |
735a0e33 | 324 | { |
a813c111 | 325 | rtx block_head = BB_HEAD (e->dest); |
735a0e33 UD |
326 | |
327 | draw_edge (fp, INSN_UID (tmp_rtx), | |
328 | INSN_UID (block_head), | |
e881bb1b RH |
329 | next_insn != block_head, |
330 | (e->flags & EDGE_ABNORMAL ? 2 : 0)); | |
735a0e33 | 331 | |
e881bb1b | 332 | if (block_head == next_insn) |
735a0e33 UD |
333 | edge_printed = 1; |
334 | } | |
e881bb1b | 335 | else |
735a0e33 UD |
336 | { |
337 | draw_edge (fp, INSN_UID (tmp_rtx), 999999, | |
e881bb1b RH |
338 | next_insn != 0, |
339 | (e->flags & EDGE_ABNORMAL ? 2 : 0)); | |
735a0e33 UD |
340 | |
341 | if (next_insn == 0) | |
342 | edge_printed = 1; | |
343 | } | |
735a0e33 UD |
344 | } |
345 | } | |
346 | ||
347 | if (!edge_printed) | |
348 | { | |
349 | /* Don't print edges to barriers. */ | |
350 | if (next_insn == 0 | |
4b4bf941 | 351 | || !BARRIER_P (next_insn)) |
735a0e33 UD |
352 | draw_edge (fp, XINT (tmp_rtx, 0), |
353 | next_insn ? INSN_UID (next_insn) : 999999, 0, 0); | |
354 | else | |
355 | { | |
e881bb1b RH |
356 | /* We draw the remaining edges in class 3. We have |
357 | to skip over the barrier since these nodes are | |
735a0e33 UD |
358 | not printed at all. */ |
359 | do | |
360 | next_insn = NEXT_INSN (next_insn); | |
361 | while (next_insn | |
4b4bf941 JQ |
362 | && (NOTE_P (next_insn) |
363 | || BARRIER_P (next_insn))); | |
735a0e33 UD |
364 | |
365 | draw_edge (fp, XINT (tmp_rtx, 0), | |
e881bb1b | 366 | next_insn ? INSN_UID (next_insn) : 999999, 0, 3); |
735a0e33 UD |
367 | } |
368 | } | |
369 | } | |
370 | ||
371 | dump_for_graph = 0; | |
372 | ||
373 | end_fct (fp); | |
4da896b2 MM |
374 | |
375 | /* Clean up. */ | |
376 | free (start); | |
377 | free (end); | |
378 | free (in_bb_p); | |
735a0e33 UD |
379 | } |
380 | ||
381 | fclose (fp); | |
382 | } | |
383 | ||
384 | ||
385 | /* Similar as clean_dump_file, but this time for graph output files. */ | |
400500c4 | 386 | |
735a0e33 | 387 | void |
9f8628ba | 388 | clean_graph_dump_file (const char *base) |
735a0e33 UD |
389 | { |
390 | size_t namelen = strlen (base); | |
735a0e33 | 391 | size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; |
9f8628ba | 392 | char *buf = alloca (namelen + extlen); |
735a0e33 UD |
393 | FILE *fp; |
394 | ||
395 | memcpy (buf, base, namelen); | |
9f8628ba | 396 | memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); |
735a0e33 UD |
397 | |
398 | fp = fopen (buf, "w"); | |
399 | ||
400 | if (fp == NULL) | |
fa6ef813 | 401 | fatal_error ("can't open %s: %m", buf); |
735a0e33 | 402 | |
282899df NS |
403 | gcc_assert (graph_dump_format == vcg); |
404 | fputs ("graph: {\nport_sharing: no\n", fp); | |
735a0e33 UD |
405 | |
406 | fclose (fp); | |
407 | } | |
408 | ||
409 | ||
410 | /* Do final work on the graph output file. */ | |
411 | void | |
9f8628ba | 412 | finish_graph_dump_file (const char *base) |
735a0e33 UD |
413 | { |
414 | size_t namelen = strlen (base); | |
735a0e33 | 415 | size_t extlen = strlen (graph_ext[graph_dump_format]) + 1; |
9f8628ba | 416 | char *buf = alloca (namelen + extlen); |
735a0e33 UD |
417 | FILE *fp; |
418 | ||
419 | memcpy (buf, base, namelen); | |
9f8628ba | 420 | memcpy (buf + namelen, graph_ext[graph_dump_format], extlen); |
735a0e33 UD |
421 | |
422 | fp = fopen (buf, "a"); | |
423 | if (fp != NULL) | |
424 | { | |
282899df NS |
425 | gcc_assert (graph_dump_format == vcg); |
426 | fputs ("}\n", fp); | |
735a0e33 UD |
427 | fclose (fp); |
428 | } | |
429 | } |