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