graph.c 9.52 KB
Newer Older
1
/* Output routines for graphical representation.
2
   Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2007
3
   Free Software Foundation, Inc.
4 5
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.

6
This file is part of GCC.
7

8 9
GCC is free software; you can redistribute it and/or modify it under
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 14 15 16
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
17

18
You should have received a copy of the GNU General Public License
19 20
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
21 22 23

#include <config.h>
#include "system.h"
24 25
#include "coretypes.h"
#include "tm.h"
26 27 28
#include "rtl.h"
#include "flags.h"
#include "output.h"
29
#include "function.h"
30
#include "hard-reg-set.h"
31
#include "obstack.h"
32 33
#include "basic-block.h"
#include "toplev.h"
34
#include "graph.h"
35

36
static const char *const graph_ext[] =
37 38 39 40 41
{
  /* no_graph */ "",
  /* vcg */      ".vcg",
};

42 43 44 45 46 47
static void start_fct (FILE *);
static void start_bb (FILE *, int);
static void node_data (FILE *, rtx);
static void draw_edge (FILE *, int, int, int, int);
static void end_fct (FILE *);
static void end_bb (FILE *);
48

49 50
/* Output text for new basic block.  */
static void
51
start_fct (FILE *fp)
52 53 54 55 56 57
{
  switch (graph_dump_format)
    {
    case vcg:
      fprintf (fp, "\
graph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n",
58
	       current_function_name (), current_function_name ());
59 60 61 62 63 64 65
      break;
    case no_graph:
      break;
    }
}

static void
66
start_bb (FILE *fp, int bb)
67
{
68 69 70 71
#if 0
  reg_set_iterator rsi;
#endif

72 73 74 75 76 77
  switch (graph_dump_format)
    {
    case vcg:
      fprintf (fp, "\
graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\
label: \"basic block %d",
78
	       current_function_name (), bb, bb);
79 80 81 82 83 84
      break;
    case no_graph:
      break;
    }

#if 0
85
  /* FIXME Should this be printed?  It makes the graph significantly larger.  */
86 87 88

  /* Print the live-at-start register list.  */
  fputc ('\n', fp);
89 90 91 92 93 94
  EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i, rsi)
    {
      fprintf (fp, " %d", i);
      if (i < FIRST_PSEUDO_REGISTER)
	fprintf (fp, " [%s]", reg_names[i]);
    }
95 96 97 98 99 100 101 102 103 104 105 106
#endif

  switch (graph_dump_format)
    {
    case vcg:
      fputs ("\"\n\n", fp);
      break;
    case no_graph:
      break;
    }
}

107
static void
108
node_data (FILE *fp, rtx tmp_rtx)
109 110 111 112 113 114 115 116 117 118
{
  if (PREV_INSN (tmp_rtx) == 0)
    {
      /* This is the first instruction.  Add an edge from the starting
	 block.  */
      switch (graph_dump_format)
	{
	case vcg:
	  fprintf (fp, "\
edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n",
119 120
		   current_function_name (),
		   current_function_name (), XINT (tmp_rtx, 0));
121 122 123 124 125 126 127 128 129 130 131
	  break;
	case no_graph:
	  break;
	}
    }

  switch (graph_dump_format)
    {
    case vcg:
      fprintf (fp, "node: {\n  title: \"%s.%d\"\n  color: %s\n  \
label: \"%s %d\n",
132
	       current_function_name (), XINT (tmp_rtx, 0),
133 134 135 136 137
	       NOTE_P (tmp_rtx) ? "lightgrey"
	       : NONJUMP_INSN_P (tmp_rtx) ? "green"
	       : JUMP_P (tmp_rtx) ? "darkgreen"
	       : CALL_P (tmp_rtx) ? "darkgreen"
	       : LABEL_P (tmp_rtx) ?  "\
138 139 140 141 142 143 144 145
darkgrey\n  shape: ellipse" : "white",
	       GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0));
      break;
    case no_graph:
      break;
    }

  /* Print the RTL.  */
146
  if (NOTE_P (tmp_rtx))
147
    {
148 149
      const char *name;
      name =  GET_NOTE_INSN_NAME (NOTE_KIND (tmp_rtx));
150
      fprintf (fp, " %s", name);
151
    }
152
  else if (INSN_P (tmp_rtx))
153
    print_rtl_single (fp, PATTERN (tmp_rtx));
154
  else
155
    print_rtl_single (fp, tmp_rtx);
156 157 158 159 160 161 162 163 164 165 166 167

  switch (graph_dump_format)
    {
    case vcg:
      fputs ("\"\n}\n", fp);
      break;
    case no_graph:
      break;
    }
}

static void
168
draw_edge (FILE *fp, int from, int to, int bb_edge, int class)
169
{
170
  const char * color;
171 172 173
  switch (graph_dump_format)
    {
    case vcg:
174 175 176 177 178 179 180
      color = "";
      if (class == 2)
	color = "color: red ";
      else if (bb_edge)
	color = "color: blue ";
      else if (class == 3)
	color = "color: green ";
181 182
      fprintf (fp,
	       "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
183 184
	       current_function_name (), from,
	       current_function_name (), to, color);
185 186 187 188 189 190 191 192 193 194
      if (class)
	fprintf (fp, "class: %d ", class);
      fputs ("}\n", fp);
      break;
    case no_graph:
      break;
    }
}

static void
195
end_bb (FILE *fp)
196 197 198 199 200 201 202 203 204 205 206 207
{
  switch (graph_dump_format)
    {
    case vcg:
      fputs ("}\n", fp);
      break;
    case no_graph:
      break;
    }
}

static void
208
end_fct (FILE *fp)
209 210 211 212 213
{
  switch (graph_dump_format)
    {
    case vcg:
      fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n",
214
	       current_function_name ());
215 216 217 218 219 220 221 222 223
      break;
    case no_graph:
      break;
    }
}

/* Like print_rtl, but also print out live information for the start of each
   basic block.  */
void
224
print_rtl_graph_with_bb (const char *base, rtx rtx_first)
225
{
226
  rtx tmp_rtx;
227 228
  size_t namelen = strlen (base);
  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
229
  char *buf = alloca (namelen + extlen);
230 231
  FILE *fp;

232 233
  if (basic_block_info == NULL)
    return;
234 235

  memcpy (buf, base, namelen);
236
  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
237 238 239 240 241 242 243 244 245 246 247

  fp = fopen (buf, "a");
  if (fp == NULL)
    return;

  if (rtx_first == 0)
    fprintf (fp, "(nil)\n");
  else
    {
      enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
      int max_uid = get_max_uid ();
248 249 250
      int *start = XNEWVEC (int, max_uid);
      int *end = XNEWVEC (int, max_uid);
      enum bb_state *in_bb_p = XNEWVEC (enum bb_state, max_uid);
251
      basic_block bb;
252
      int i;
253

254
      for (i = 0; i < max_uid; ++i)
255
	{
256 257
	  start[i] = end[i] = -1;
	  in_bb_p[i] = NOT_IN_BB;
258 259
	}

260
      FOR_EACH_BB_REVERSE (bb)
261 262
	{
	  rtx x;
263 264 265
	  start[INSN_UID (BB_HEAD (bb))] = bb->index;
	  end[INSN_UID (BB_END (bb))] = bb->index;
	  for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x))
266 267 268 269
	    {
	      in_bb_p[INSN_UID (x)]
		= (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
		 ? IN_ONE_BB : IN_MULTIPLE_BB;
270
	      if (x == BB_END (bb))
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
		break;
	    }
	}

      /* Tell print-rtl that we want graph output.  */
      dump_for_graph = 1;

      /* Start new function.  */
      start_fct (fp);

      for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx;
	   tmp_rtx = NEXT_INSN (tmp_rtx))
	{
	  int edge_printed = 0;
	  rtx next_insn;

	  if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
	    {
289
	      if (BARRIER_P (tmp_rtx))
290
		continue;
291
	      if (NOTE_P (tmp_rtx)
292 293 294 295
		  && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB))
		continue;
	    }

296
	  if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
297 298
	    {
	      /* We start a subgraph for each basic block.  */
299
	      start_bb (fp, i);
300

301
	      if (i == 0)
302 303 304 305
		draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
	    }

	  /* Print the data for this node.  */
306
	  node_data (fp, tmp_rtx);
307 308
	  next_insn = next_nonnote_insn (tmp_rtx);

309
	  if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
310
	    {
311
	      edge e;
312
	      edge_iterator ei;
313

314
	      bb = BASIC_BLOCK (i);
315 316

	      /* End of the basic block.  */
317
	      end_bb (fp);
318 319 320

	      /* Now specify the edges to all the successors of this
		 basic block.  */
321
	      FOR_EACH_EDGE (e, ei, bb->succs)
322
		{
323
		  if (e->dest != EXIT_BLOCK_PTR)
324
		    {
325
		      rtx block_head = BB_HEAD (e->dest);
326 327 328

		      draw_edge (fp, INSN_UID (tmp_rtx),
				 INSN_UID (block_head),
329 330
				 next_insn != block_head,
				 (e->flags & EDGE_ABNORMAL ? 2 : 0));
331

332
		      if (block_head == next_insn)
333 334
			edge_printed = 1;
		    }
335
		  else
336 337
		    {
		      draw_edge (fp, INSN_UID (tmp_rtx), 999999,
338 339
				 next_insn != 0,
				 (e->flags & EDGE_ABNORMAL ? 2 : 0));
340 341 342 343 344 345 346 347 348 349 350

		      if (next_insn == 0)
			edge_printed = 1;
		    }
		}
	    }

	  if (!edge_printed)
	    {
	      /* Don't print edges to barriers.  */
	      if (next_insn == 0
351
		  || !BARRIER_P (next_insn))
352 353 354 355
		draw_edge (fp, XINT (tmp_rtx, 0),
			   next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
	      else
		{
356 357
		  /* We draw the remaining edges in class 3.  We have
		     to skip over the barrier since these nodes are
358 359 360 361
		     not printed at all.  */
		  do
		    next_insn = NEXT_INSN (next_insn);
		  while (next_insn
362 363
			 && (NOTE_P (next_insn)
			     || BARRIER_P (next_insn)));
364 365

		  draw_edge (fp, XINT (tmp_rtx, 0),
366
			     next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
367 368 369 370 371 372 373
		}
	    }
	}

      dump_for_graph = 0;

      end_fct (fp);
374 375 376 377 378

      /* Clean up.  */
      free (start);
      free (end);
      free (in_bb_p);
379 380 381 382 383 384 385
    }

  fclose (fp);
}


/* Similar as clean_dump_file, but this time for graph output files.  */
386

387
void
388
clean_graph_dump_file (const char *base)
389 390 391
{
  size_t namelen = strlen (base);
  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
392
  char *buf = alloca (namelen + extlen);
393 394 395
  FILE *fp;

  memcpy (buf, base, namelen);
396
  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
397 398 399 400

  fp = fopen (buf, "w");

  if (fp == NULL)
401
    fatal_error ("can't open %s: %m", buf);
402

403 404
  gcc_assert (graph_dump_format == vcg);
  fputs ("graph: {\nport_sharing: no\n", fp);
405 406 407 408 409 410 411

  fclose (fp);
}


/* Do final work on the graph output file.  */
void
412
finish_graph_dump_file (const char *base)
413 414 415
{
  size_t namelen = strlen (base);
  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
416
  char *buf = alloca (namelen + extlen);
417 418 419
  FILE *fp;

  memcpy (buf, base, namelen);
420
  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
421 422 423 424

  fp = fopen (buf, "a");
  if (fp != NULL)
    {
425 426
      gcc_assert (graph_dump_format == vcg);
      fputs ("}\n", fp);
427 428 429
      fclose (fp);
    }
}