public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch] Rework RTL CFG graph dumping to dump DOT format
@ 2012-11-23  9:47 Steven Bosscher
  2012-11-26 15:46 ` Richard Biener
  0 siblings, 1 reply; 7+ messages in thread
From: Steven Bosscher @ 2012-11-23  9:47 UTC (permalink / raw)
  To: GCC Patches; +Cc: rsandifo

[-- Attachment #1: Type: text/plain, Size: 892 bytes --]

Hello,

The graph.[ch] code to dump the CFG for viewing with VCG is quite
broken and hasn't been updated to follow the advances in the CFG
infrastructure.

The attached patch is the first in a series of patches I have planned
to update the CFG-as-graph dumping code to dump GraphViz DOT input
instead. The attached archive is an example input/output.

There's still quite a lot of work to be done:
- use pretty-print in the slim RTL dumping
- move the escaped-string printing into pretty-print
- make the basic block content dumping a cfghook
- make these dumps work for GIMPLE also

For the moment, this is a good starting point.

Obviously there are no changes in code generation due to this patch,
so IMHO this patch (and the rest of the series) should be safe for
stage3. Hopefully everyone else agrees :-)

Bootstrapped&tested on powerpc64-unknown-linux-gnu. OK for trunk?

Ciao!
Steven

[-- Attachment #2: t.tar.gz --]
[-- Type: application/x-gzip, Size: 75309 bytes --]

[-- Attachment #3: cfg_graph_dot.diff --]
[-- Type: application/octet-stream, Size: 35250 bytes --]

gcc/
	* doc/invoke.texi: Remove -dv documentation.  Fix up graph dump related
	documentation.  Document the '-graph' dump option.  Complete the '-slim'
	dump option documentation.

	* common.opt (Variable graph_dump_format): Remove.
	* flag-types.h (enum graph_dump_types): Remove.
	* flags.h (dump_for_graph): Remove.
	* opts.c (decode_d_option): Remove -dv handling.
	* sched-int.h (print_insn, print_pattern, print_value): Move prototypes
	from here ...
	* rtl.h: ...to here.  Add note that these functions ought to be in
	another file.
	* sched-vis.c (print_insn): Add detailed dump for insn notes.
	* print-rtl.c (dump_for_graph): Remove.
	(print_rtx): Remove dump_for_graph related code.
	* graph.c: Almost complete re-write to dump DOT (GraphViz) dumps
	instead of VCG dumps.
	* graph.h (print_rtl_graph_with_bb): Update prototype.
	* passes.c (finish_optimization_passes): Fix profile dump finishing.
	Unconditionally loop over graph dumps to finalize.
	(execute_function_dump): Split code to dump graphs to separate block.
	(execute_one_pass): Don't set TDF_GRAPH here, let the dump option
	decoders do their job.

	* ddg.c (vcg_print_ddg): Make it a DEBUG_FUNCTION.
	* toplev.c: Don't include graph.h.
	* tree-optimize.c: Don't include graph.h.

testsuite/
	* testsuite/gcc.dg/20050811-1.c: Change -dv option to -graph option
	to -fdump-rtl-all.
	* testsuite/gcc.dg/pr37858.c: Remove -dv option.

Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 193650)
+++ doc/invoke.texi	(working copy)
@@ -5369,7 +5369,7 @@ appended with a sequential number starting from 1.
 comma-separated list of function ranges or assembler names.  Each range is a number
 pair separated by a colon.  The range is inclusive in both ends.  If the range
 is trivial, the number pair can be simplified as a single number.  If the
-function's cgraph node's @var{uid} falls within one of the specified ranges,
+function's call graph node's @var{uid} falls within one of the specified ranges,
 the @var{pass} is disabled for that function.  The @var{uid} is shown in the
 function header of a dump file, and the pass names can be dumped by using
 option @option{-fdump-passes}.
@@ -5725,12 +5725,6 @@ also printed.
 Dump the RTL in the assembler output as a comment before each instruction.
 Also turns on @option{-dp} annotation.
 
-@item -dv
-@opindex dv
-For each of the other indicated dump files (@option{-fdump-rtl-@var{pass}}),
-dump a representation of the control flow graph suitable for viewing with VCG
-to @file{@var{file}.@var{pass}.vcg}.
-
 @item -dx
 @opindex dx
 Just generate RTL for a function instead of compiling it.  Usually used
@@ -5839,10 +5833,16 @@ If @code{DECL_ASSEMBLER_NAME} has been set for a g
 in the dump instead of @code{DECL_NAME}.  Its primary use is ease of
 use working backward from mangled names in the assembly file.
 @item slim
-Inhibit dumping of members of a scope or body of a function merely
-because that scope has been reached.  Only dump such items when they
-are directly reachable by some other path.  When dumping pretty-printed
-trees, this option inhibits dumping the bodies of control structures.
+When dumping front-end intermediate representations, inhibit dumping
+of members of a scope or body of a function merely because that scope
+has been reached.  Only dump such items when they are directly reachable
+by some other path.
+
+When dumping pretty-printed trees, this option inhibits dumping the
+bodies of control structures.
+
+When dumping RTL, print the RTL in slim (condensed) form instead of
+the default LISP-like representation.
 @item raw
 Print a raw representation of the tree.  By default, trees are
 pretty-printed into a C-like representation.
@@ -5854,6 +5854,16 @@ Enable dumping various statistics about the pass (
 option).
 @item blocks
 Enable showing basic block boundaries (disabled in raw dumps).
+@item graph
+For each of the other indicated dump files (@option{-fdump-rtl-@var{pass}}),
+dump a representation of the control flow graph suitable for viewing with
+GraphViz to @file{@var{file}.@var{passid}.@var{pass}.dot}.  Note that if
+the file contains more than one function, the generated file cannot be
+used directly by GraphViz@.  You must cut and paste each function's
+graph into its own separate file first.
+
+This option currently only works for RTL dumps, and the RTL is always
+dumped in slim form.
 @item vops
 Enable showing virtual operands for every statement.
 @item lineno
Index: common.opt
===================================================================
--- common.opt	(revision 193650)
+++ common.opt	(working copy)
@@ -174,9 +174,6 @@ int rtl_dump_and_exit
 Variable
 int flag_print_asm_name
 
-Variable
-enum graph_dump_types graph_dump_format = no_graph
-
 ; Name of top-level original source file (what was input to cpp).
 ; This comes from the #-command at the beginning of the actual input.
 ; If there isn't any there, then this is the cc1 input file name.
Index: flag-types.h
===================================================================
--- flag-types.h	(revision 193650)
+++ flag-types.h	(working copy)
@@ -141,13 +141,6 @@ enum excess_precision
   EXCESS_PRECISION_STANDARD
 };
 
-/* Selection of the graph form.  */
-enum graph_dump_types
-{
-  no_graph = 0,
-  vcg
-};
-
 /* Type of stack check.  */
 enum stack_check_type
 {
Index: flags.h
===================================================================
--- flags.h	(revision 193650)
+++ flags.h	(working copy)
@@ -89,9 +89,6 @@ extern struct target_flag_state *this_target_flag_
 #define flag_excess_precision \
   (this_target_flag_state->x_flag_excess_precision)
 
-/* Nonzero if we dump in VCG format, not plain text.  */
-extern int dump_for_graph;
-
 /* Returns TRUE if generated code should match ABI version N or
    greater is in use.  */
 
Index: opts.c
===================================================================
--- opts.c	(revision 193650)
+++ opts.c	(working copy)
@@ -1982,9 +1982,6 @@ decode_d_option (const char *arg, struct gcc_optio
 	opts->x_flag_dump_rtl_in_asm = 1;
 	opts->x_flag_print_asm_name = 1;
 	break;
-      case 'v':
-	opts->x_graph_dump_format = vcg;
-	break;
       case 'x':
 	opts->x_rtl_dump_and_exit = 1;
 	break;
Index: sched-int.h
===================================================================
--- sched-int.h	(revision 193650)
+++ sched-int.h	(working copy)
@@ -1578,11 +1578,5 @@ extern void sd_debug_lists (rtx, sd_list_types_def
 
 #endif /* INSN_SCHEDULING */
 
-/* Functions in sched-vis.c.  These must be outside INSN_SCHEDULING as
-   sched-vis.c is compiled always.  */
-extern void print_insn (char *, const_rtx, int);
-extern void print_pattern (char *, const_rtx, int);
-extern void print_value (char *, const_rtx, int);
-
 #endif /* GCC_SCHED_INT_H */
 
Index: rtl.h
===================================================================
--- rtl.h	(revision 193650)
+++ rtl.h	(working copy)
@@ -2605,6 +2605,14 @@ extern int print_rtl_single (FILE *, const_rtx);
 extern int print_rtl_single_with_indent (FILE *, const_rtx, int);
 extern void print_inline_rtx (FILE *, const_rtx, int);
 
+/* Functions in sched-vis.c.  These must be outside INSN_SCHEDULING as
+   sched-vis.c is compiled always.  FIXME: Ideally these functions would
+   not be in sched-vis.c but in rtl.c, because they are not only used
+   by the scheduler anymore but for all "slim" RTL dumping.  */
+extern void print_insn (char *, const_rtx, int);
+extern void print_pattern (char *, const_rtx, int);
+extern void print_value (char *, const_rtx, int);
+
 /* In function.c */
 extern void reposition_prologue_and_epilogue_notes (void);
 extern int prologue_epilogue_contains (const_rtx);
Index: sched-vis.c
===================================================================
--- sched-vis.c	(revision 193650)
+++ sched-vis.c	(working copy)
@@ -782,12 +782,53 @@ print_insn (char *buf, const_rtx x, int verbose)
       sprintf (buf, "i%4d: barrier", INSN_UID (x));
       break;
     case NOTE:
-      sprintf (buf, " %4d %s", INSN_UID (x),
-	       GET_NOTE_INSN_NAME (NOTE_KIND (x)));
-      break;
+      {
+        int uid = INSN_UID (x);
+        const char *note_name = GET_NOTE_INSN_NAME (NOTE_KIND (x));
+	switch (NOTE_KIND (x))
+	  {
+	  case NOTE_INSN_EH_REGION_BEG:
+	  case NOTE_INSN_EH_REGION_END:
+	    sprintf (buf, " %4d %s %d", uid, note_name,
+		     NOTE_EH_HANDLER (x));
+	    break;
+
+	  case NOTE_INSN_BLOCK_BEG:
+	  case NOTE_INSN_BLOCK_END:
+	    sprintf (buf, " %4d %s %d", uid, note_name,
+		     BLOCK_NUMBER (NOTE_BLOCK (x)));
+	    break;
+
+	  case NOTE_INSN_BASIC_BLOCK:
+	    sprintf (buf, " %4d %s %d", uid, note_name,
+		     NOTE_BASIC_BLOCK (x)->index);
+	    break;
+
+	  case NOTE_INSN_DELETED_LABEL:
+	  case NOTE_INSN_DELETED_DEBUG_LABEL:
+	    {
+	      const char *label = NOTE_DELETED_LABEL_NAME (x);
+	      if (label == NULL)
+		label = "";
+	      sprintf (buf, " %4d %s (\"%s\")", uid, note_name, label);
+	    }
+	    break;
+
+	  case NOTE_INSN_VAR_LOCATION:
+	    print_pattern (t, NOTE_VAR_LOCATION (x), verbose);
+	    sprintf (buf, " %4d %s {%s}", uid, note_name, t);
+	    break;
+
+	  default:
+	    sprintf (buf, " %4d %s", uid, note_name);
+	    break;
+	  }
+	break;
+      }
     default:
       sprintf (buf, "i%4d  <What %s?>", INSN_UID (x),
 	       GET_RTX_NAME (GET_CODE (x)));
+      break;
     }
 }				/* print_insn */
 
Index: print-rtl.c
===================================================================
--- print-rtl.c	(revision 193650)
+++ print-rtl.c	(working copy)
@@ -77,9 +77,6 @@ int flag_dump_unnumbered_links = 0;
 /* Nonzero means use simplified format without flags, modes, etc.  */
 int flag_simple = 0;
 
-/* Nonzero if we are dumping graphical description.  */
-int dump_for_graph;
-
 #ifndef GENERATOR_FILE
 void
 print_mem_expr (FILE *outfile, const_tree expr)
@@ -124,74 +121,62 @@ print_rtx (const_rtx in_rtx)
 
   is_insn = INSN_P (in_rtx);
 
-  /* When printing in VCG format we write INSNs, NOTE, LABEL, and BARRIER
-     in separate nodes and therefore have to handle them special here.  */
-  if (dump_for_graph
-      && (is_insn || NOTE_P (in_rtx)
-	  || LABEL_P (in_rtx) || BARRIER_P (in_rtx)))
-    {
-      i = 3;
-      indent = 0;
-    }
+  /* Print name of expression code.  */
+  if (flag_simple && CONST_INT_P (in_rtx))
+    fputc ('(', outfile);
   else
+    fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx)));
+
+  if (! flag_simple)
     {
-      /* Print name of expression code.  */
-      if (flag_simple && CONST_INT_P (in_rtx))
-	fputc ('(', outfile);
-      else
-	fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx)));
+      if (RTX_FLAG (in_rtx, in_struct))
+	fputs ("/s", outfile);
 
-      if (! flag_simple)
-	{
-	  if (RTX_FLAG (in_rtx, in_struct))
-	    fputs ("/s", outfile);
+      if (RTX_FLAG (in_rtx, volatil))
+	fputs ("/v", outfile);
 
-	  if (RTX_FLAG (in_rtx, volatil))
-	    fputs ("/v", outfile);
+      if (RTX_FLAG (in_rtx, unchanging))
+	fputs ("/u", outfile);
 
-	  if (RTX_FLAG (in_rtx, unchanging))
-	    fputs ("/u", outfile);
+      if (RTX_FLAG (in_rtx, frame_related))
+	fputs ("/f", outfile);
 
-	  if (RTX_FLAG (in_rtx, frame_related))
-	    fputs ("/f", outfile);
+      if (RTX_FLAG (in_rtx, jump))
+	fputs ("/j", outfile);
 
-	  if (RTX_FLAG (in_rtx, jump))
-	    fputs ("/j", outfile);
+      if (RTX_FLAG (in_rtx, call))
+	fputs ("/c", outfile);
 
-	  if (RTX_FLAG (in_rtx, call))
-	    fputs ("/c", outfile);
+      if (RTX_FLAG (in_rtx, return_val))
+	fputs ("/i", outfile);
 
-	  if (RTX_FLAG (in_rtx, return_val))
-	    fputs ("/i", outfile);
+      /* Print REG_NOTE names for EXPR_LIST and INSN_LIST.  */
+      if ((GET_CODE (in_rtx) == EXPR_LIST
+	   || GET_CODE (in_rtx) == INSN_LIST)
+	  && (int)GET_MODE (in_rtx) < REG_NOTE_MAX)
+	fprintf (outfile, ":%s",
+		 GET_REG_NOTE_NAME (GET_MODE (in_rtx)));
 
-	  /* Print REG_NOTE names for EXPR_LIST and INSN_LIST.  */
-	  if ((GET_CODE (in_rtx) == EXPR_LIST
-	       || GET_CODE (in_rtx) == INSN_LIST)
-	      && (int)GET_MODE (in_rtx) < REG_NOTE_MAX)
-	    fprintf (outfile, ":%s",
-		     GET_REG_NOTE_NAME (GET_MODE (in_rtx)));
+      /* For other rtl, print the mode if it's not VOID.  */
+      else if (GET_MODE (in_rtx) != VOIDmode)
+	fprintf (outfile, ":%s", GET_MODE_NAME (GET_MODE (in_rtx)));
 
-	  /* For other rtl, print the mode if it's not VOID.  */
-	  else if (GET_MODE (in_rtx) != VOIDmode)
-	    fprintf (outfile, ":%s", GET_MODE_NAME (GET_MODE (in_rtx)));
-
 #ifndef GENERATOR_FILE
-	  if (GET_CODE (in_rtx) == VAR_LOCATION)
-	    {
-	      if (TREE_CODE (PAT_VAR_LOCATION_DECL (in_rtx)) == STRING_CST)
-		fputs (" <debug string placeholder>", outfile);
-	      else
-		print_mem_expr (outfile, PAT_VAR_LOCATION_DECL (in_rtx));
-	      fputc (' ', outfile);
-	      print_rtx (PAT_VAR_LOCATION_LOC (in_rtx));
-	      if (PAT_VAR_LOCATION_STATUS (in_rtx)
-		  == VAR_INIT_STATUS_UNINITIALIZED)
-		fprintf (outfile, " [uninit]");
-	      sawclose = 1;
-	      i = GET_RTX_LENGTH (VAR_LOCATION);
-	    }
-#endif
+      if (GET_CODE (in_rtx) == VAR_LOCATION)
+	{
+	  if (TREE_CODE (PAT_VAR_LOCATION_DECL (in_rtx)) == STRING_CST)
+	    fputs (" <debug string placeholder>", outfile);
+	  else
+	    print_mem_expr (outfile, PAT_VAR_LOCATION_DECL (in_rtx));
+	  fputc (' ', outfile);
+	  print_rtx (PAT_VAR_LOCATION_LOC (in_rtx));
+	  if (PAT_VAR_LOCATION_STATUS (in_rtx)
+	      == VAR_INIT_STATUS_UNINITIALIZED)
+	    fprintf (outfile, " [uninit]");
+	  sawclose = 1;
+	  i = GET_RTX_LENGTH (VAR_LOCATION);
 	}
+#endif
     }
 
 #ifndef GENERATOR_FILE
@@ -217,14 +202,9 @@ print_rtx (const_rtx in_rtx)
       string:
 
 	if (str == 0)
-	  fputs (dump_for_graph ? " \\\"\\\"" : " \"\"", outfile);
+	  fputs (" \"\"", outfile);
 	else
-	  {
-	    if (dump_for_graph)
-	      fprintf (outfile, " (\\\"%s\\\")", str);
-	    else
-	      fprintf (outfile, " (\"%s\")", str);
-	  }
+	  fprintf (outfile, " (\"%s\")", str);
 	sawclose = 1;
 	break;
 
@@ -652,15 +632,7 @@ print_rtx (const_rtx in_rtx)
       break;
     }
 
-  if (dump_for_graph
-      && (is_insn || NOTE_P (in_rtx)
-	  || LABEL_P (in_rtx) || BARRIER_P (in_rtx)))
-    sawclose = 0;
-  else
-    {
-      fputc (')', outfile);
-      sawclose = 1;
-    }
+  fputc (')', outfile);
 }
 
 /* Print an rtx on the current line of FILE.  Initially indent IND
Index: graph.c
===================================================================
--- graph.c	(revision 193650)
+++ graph.c	(working copy)
@@ -1,7 +1,8 @@
 /* Output routines for graphical representation.
-   Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2007, 2008, 2010
+   Copyright (C) 1998-2012
    Free Software Foundation, Inc.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+   Rewritten for DOT output by Steven Bosscher, 2012.
 
 This file is part of GCC.
 
@@ -22,396 +23,242 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "rtl.h"
-#include "flags.h"
-#include "function.h"
-#include "hard-reg-set.h"
-#include "obstack.h"
+#include "diagnostic-core.h" /* for fatal_error */
+#include "sbitmap.h"
 #include "basic-block.h"
-#include "diagnostic-core.h"
+#include "rtl.h"
+#include "tree.h"
 #include "graph.h"
-#include "emit-rtl.h"
 
-static const char *const graph_ext[] =
+/* DOT files with the .dot extension are recognized as document templates
+   by a well-known piece of word processing software out of Redmond, WA.
+   Therefore some recommend using the .gv extension instead.  Obstinately
+   ignore that recommendatition...  */
+static const char *const graph_ext = ".dot";
+
+/* Open a file with MODE for dumping our graph to.
+   Return the file pointer.  */
+static FILE *
+open_graph_file (const char *base, const char *mode)
 {
-  /* no_graph */ "",
-  /* vcg */      ".vcg",
-};
+  size_t namelen = strlen (base);
+  size_t extlen = strlen (graph_ext) + 1;
+  char *buf = XALLOCAVEC (char, namelen + extlen);
+  FILE *fp;
 
-/* The flag to indicate if output is inside of a building block.  */
-static int inbb = 0;
+  memcpy (buf, base, namelen);
+  memcpy (buf + namelen, graph_ext, extlen);
 
-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 *);
+  fp = fopen (buf, mode);
+  if (fp == NULL)
+    fatal_error ("can%'t open %s: %m", buf);
 
-/* Output text for new basic block.  */
-static void
-start_fct (FILE *fp)
+  return fp;
+}
+
+/* Print the output from print_insn or print_pattern with GraphViz-special
+   characters escaped as necessary.  */
+void
+print_escaped_line (FILE *fp, const char *buf)
 {
-  switch (graph_dump_format)
+  const char *p = buf;
+
+  while (*p)
     {
-    case vcg:
-      fprintf (fp, "\
-graph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n",
-	       current_function_name (), current_function_name ());
-      break;
-    case no_graph:
-      break;
+      switch (*p)
+	{
+	case '\n':
+	  /* Print newlines as a left-aligned newline.  */
+	  fputs ("\\l\\\n", fp);
+	  break;
+
+	case '{':
+	case '}':
+	case '<':
+	case '>':
+	case '|':
+	case ' ':
+	  /* These characters have to be escaped to work with record-shape nodes.  */
+	  fputc ('\\', fp);
+	  /* fall through */
+	default:
+	  fputc (*p, fp);
+	  break;
+	}
+      p++;
     }
+  fputs ("\\l\\\n", fp);
 }
 
+/* Draw a basic block BB belonging to the function with FNDECL_UID
+   as its unique number.  */
 static void
-start_bb (FILE *fp, int bb)
+draw_cfg_node (FILE *fp, int fndecl_uid, basic_block bb)
 {
-#if 0
-  reg_set_iterator rsi;
-#endif
+  rtx insn;
+  bool first = true;
+  const char *shape;
+  const char *fillcolor;
 
-  switch (graph_dump_format)
+  if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
     {
-    case vcg:
-      fprintf (fp, "\
-graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\
-label: \"basic block %d",
-	       current_function_name (), bb, bb);
-      inbb = 1; /* Now We are inside of a building block.  */
-      break;
-    case no_graph:
-      break;
+      shape = "Mdiamond";
+      fillcolor = "white";
     }
-
-#if 0
-  /* FIXME Should this be printed?  It makes the graph significantly larger.  */
-
-  /* Print the live-at-start register list.  */
-  fputc ('\n', fp);
-  EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i, rsi)
+  else
     {
-      fprintf (fp, " %d", i);
-      if (i < FIRST_PSEUDO_REGISTER)
-	fprintf (fp, " [%s]", reg_names[i]);
+      shape = "record";
+      fillcolor =
+	BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink"
+	: BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue"
+	: "lightgrey";
     }
-#endif
 
-  switch (graph_dump_format)
-    {
-    case vcg:
-      fputs ("\"\n\n", fp);
-      break;
-    case no_graph:
-      break;
-    }
-}
+  fprintf (fp,
+	   "\tfn_%d_basic_block_%d [shape=%s,style=filled,fillcolor=%s,label=\"",
+	   fndecl_uid, bb->index, shape, fillcolor);
 
-static void
-node_data (FILE *fp, rtx tmp_rtx)
-{
-  if (PREV_INSN (tmp_rtx) == 0)
+  if (bb->index == ENTRY_BLOCK)
+    fputs ("ENTRY", fp);
+  else if (bb->index == EXIT_BLOCK)
+    fputs ("EXIT", fp);
+  else
     {
-      /* This is the first instruction.  Add an edge from the starting
-	 block.  */
-      switch (graph_dump_format)
+      fputc ('{', fp);
+      /* TODO: inter-bb stuff.  */
+      FOR_BB_INSNS (bb, insn)
 	{
-	case vcg:
-	  fprintf (fp, "\
-edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n",
-		   current_function_name (),
-		   current_function_name (), XINT (tmp_rtx, 0));
-	  break;
-	case no_graph:
-	  break;
-	}
-    }
+	  char buf[2048];
 
-  switch (graph_dump_format)
-    {
-    case vcg:
-      fprintf (fp, "node: {\n  title: \"%s.%d\"\n  color: %s\n  \
-label: \"%s %d\n",
-	       current_function_name (), XINT (tmp_rtx, 0),
-	       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) ?  "\
-darkgrey\n  shape: ellipse" : "white",
-	       GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0));
-      break;
-    case no_graph:
-      break;
-    }
+	  if (! first)
+	    fputc ('|', fp);
 
-  /* Print the RTL.  */
-  if (NOTE_P (tmp_rtx))
-    {
-      const char *name;
-      name =  GET_NOTE_INSN_NAME (NOTE_KIND (tmp_rtx));
-      fprintf (fp, " %s", name);
-    }
-  else if (INSN_P (tmp_rtx))
-    print_rtl_single (fp, PATTERN (tmp_rtx));
-  else
-    print_rtl_single (fp, tmp_rtx);
+	  print_insn (buf, insn, 1);
+	  print_escaped_line (fp, buf);
+	  if (INSN_P (insn) && REG_NOTES (insn))
+	    for (rtx note = REG_NOTES (insn); note; note = XEXP (note, 1))
+	      {
+		fprintf (fp, "      %s: ",
+			 GET_REG_NOTE_NAME (REG_NOTE_KIND (note)));
+		print_pattern (buf, XEXP (note, 0), 1);
+		print_escaped_line (fp, buf);
+	      }
 
-  switch (graph_dump_format)
-    {
-    case vcg:
-      fputs ("\"\n}\n", fp);
-      break;
-    case no_graph:
-      break;
+	  first = false;
+	}
+      fputc ('}', fp);
     }
-}
 
-static void
-draw_edge (FILE *fp, int from, int to, int bb_edge, int color_class)
-{
-  const char * color;
-  switch (graph_dump_format)
-    {
-    case vcg:
-      color = "";
-      if (color_class == 2)
-	color = "color: red ";
-      else if (bb_edge)
-	color = "color: blue ";
-      else if (color_class == 3)
-	color = "color: green ";
-      fprintf (fp,
-	       "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
-	       current_function_name (), from,
-	       current_function_name (), to, color);
-      if (color_class)
-	fprintf (fp, "class: %d ", color_class);
-      fputs ("}\n", fp);
-      break;
-    case no_graph:
-      break;
-    }
+  fputs ("\"];\n\n", fp);
 }
 
+/* Draw all successor edges of a basic block BB belonging to the function
+   with FNDECL_UID as its unique number.  */
 static void
-end_bb (FILE *fp)
+draw_cfg_node_succ_edges (FILE *fp, int fndecl_uid, basic_block bb)
 {
-  switch (graph_dump_format)
+  edge e;
+  edge_iterator ei;
+  FOR_EACH_EDGE (e, ei, bb->succs)
     {
-    case vcg:
-      /* Check if we are inside of a building block.  */
-      if (inbb != 0)
-        {
-          fputs ("}\n", fp);
-          inbb = 0; /* Now we are outside of a building block.  */
-        }
-      break;
-    case no_graph:
-      break;
-    }
-}
+      const char *style = "\"solid,bold\"";
+      const char *color = "black";
+      int weight = 10;
 
-static void
-end_fct (FILE *fp)
-{
-  switch (graph_dump_format)
-    {
-    case vcg:
-      fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n",
-	       current_function_name ());
-      break;
-    case no_graph:
-      break;
-    }
-}
-\f
-/* Like print_rtl, but also print out live information for the start of each
-   basic block.  */
-void
-print_rtl_graph_with_bb (const char *base, rtx rtx_first)
-{
-  rtx tmp_rtx;
-  size_t namelen = strlen (base);
-  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
-  char *buf = XALLOCAVEC (char, namelen + extlen);
-  FILE *fp;
-
-  if (!basic_block_info)
-    return;
-
-  memcpy (buf, base, namelen);
-  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
-
-  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 ();
-      int *start = XNEWVEC (int, max_uid);
-      int *end = XNEWVEC (int, max_uid);
-      enum bb_state *in_bb_p = XNEWVEC (enum bb_state, max_uid);
-      basic_block bb;
-      int i;
-
-      for (i = 0; i < max_uid; ++i)
+      if (e->flags & EDGE_FAKE)
 	{
-	  start[i] = end[i] = -1;
-	  in_bb_p[i] = NOT_IN_BB;
+	  style = "dotted";
+	  color = "green";
+	  weight = 0;
 	}
-
-      FOR_EACH_BB_REVERSE (bb)
+      else if (e->flags & EDGE_DFS_BACK)
 	{
-	  rtx x;
-	  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))
-	    {
-	      in_bb_p[INSN_UID (x)]
-		= (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
-		 ? IN_ONE_BB : IN_MULTIPLE_BB;
-	      if (x == BB_END (bb))
-		break;
-	    }
+	  style = "\"dotted,bold\"";
+	  color = "blue";
+	  weight = 10;
 	}
-
-      /* 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))
+      else if (e->flags & EDGE_FALLTHRU)
 	{
-	  int edge_printed = 0;
-	  rtx next_insn;
+	  color = "blue";
+	  weight = 100;
+	}
 
-	  if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
-	    {
-	      if (BARRIER_P (tmp_rtx))
-		continue;
-	      if (NOTE_P (tmp_rtx)
-		  && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB))
-		continue;
-	    }
+      if (e->flags & EDGE_ABNORMAL)
+	color = "red";
 
-	  if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
-	    {
-	      /* We start a subgraph for each basic block.  */
-	      start_bb (fp, i);
+      fprintf (fp,
+	       "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
+	       "[style=%s,color=%s,weight=%d];\n",
+	       fndecl_uid, e->src->index,
+	       fndecl_uid, e->dest->index,
+	       style, color, weight);
+    }
+}
 
-	      if (i == 0)
-		draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
-	    }
+/* Print a graphical representation of the CFG of function FUN.
+   Currently only supports RTL in cfgrtl or cfglayout mode, GIMPLE is TODO.  */
+void
+print_rtl_graph_with_bb (const char *base, tree fndecl)
+{
+  const char *funcname = fndecl_name (fndecl);
+  int fndecl_uid = DECL_UID (fndecl);
+  FILE *fp = open_graph_file (base, "a");
+  int *rpo = XNEWVEC (int, n_basic_blocks);
+  basic_block bb;
+  int i, n;
 
-	  /* Print the data for this node.  */
-	  node_data (fp, tmp_rtx);
-	  next_insn = next_nonnote_insn (tmp_rtx);
+  fprintf (fp,
+	   "subgraph \"%s\" {\n"
+	   "\tcolor=\"black\";\n"
+	   "\tlabel=\"%s\";\n",
+	   funcname, funcname);
 
-	  if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
-	    {
-	      edge e;
-	      edge_iterator ei;
+  /* First print all basic blocks.
+     Visit the blocks in reverse post order to get a good ranking
+     of the nodes.  */
+  n = pre_and_rev_post_order_compute (NULL, rpo, true);
+  for (i = 0; i < n; i++)
+    draw_cfg_node (fp, fndecl_uid, BASIC_BLOCK (rpo[i]));
 
-	      bb = BASIC_BLOCK (i);
+  /* Draw all edges at the end to get subgraphs right for GraphViz,
+     which requires nodes to be defined before edges to cluster
+     nodes properly.
 
-	      /* End of the basic block.  */
-	      end_bb (fp);
+     Draw retreating edges as not constraining, this makes the layout
+     of the graph better.  (??? Calling mark_dfs_back may change the
+     compiler's behavior when dumping, but computing back edges here
+     for ourselves is also not desirable.)  */
+  mark_dfs_back_edges ();
+  FOR_ALL_BB (bb)
+    draw_cfg_node_succ_edges (fp, fndecl_uid, bb);
 
-	      /* Now specify the edges to all the successors of this
-		 basic block.  */
-	      FOR_EACH_EDGE (e, ei, bb->succs)
-		{
-		  if (e->dest != EXIT_BLOCK_PTR)
-		    {
-		      rtx block_head = BB_HEAD (e->dest);
+  fputs ("\t}\n", fp);
 
-		      draw_edge (fp, INSN_UID (tmp_rtx),
-				 INSN_UID (block_head),
-				 next_insn != block_head,
-				 (e->flags & EDGE_ABNORMAL ? 2 : 0));
-
-		      if (block_head == next_insn)
-			edge_printed = 1;
-		    }
-		  else
-		    {
-		      draw_edge (fp, INSN_UID (tmp_rtx), 999999,
-				 next_insn != 0,
-				 (e->flags & EDGE_ABNORMAL ? 2 : 0));
-
-		      if (next_insn == 0)
-			edge_printed = 1;
-		    }
-		}
-	    }
-
-	  if (!edge_printed)
-	    {
-	      /* Don't print edges to barriers.  */
-	      if (next_insn == 0
-		  || !BARRIER_P (next_insn))
-		draw_edge (fp, XINT (tmp_rtx, 0),
-			   next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
-	      else
-		{
-		  /* We draw the remaining edges in class 3.  We have
-		     to skip over the barrier since these nodes are
-		     not printed at all.  */
-		  do
-		    next_insn = NEXT_INSN (next_insn);
-		  while (next_insn
-			 && (NOTE_P (next_insn)
-			     || BARRIER_P (next_insn)));
-
-		  draw_edge (fp, XINT (tmp_rtx, 0),
-			     next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
-		}
-	    }
-	}
-
-      dump_for_graph = 0;
-
-      end_fct (fp);
-
-      /* Clean up.  */
-      free (start);
-      free (end);
-      free (in_bb_p);
-    }
-
   fclose (fp);
 }
 
+/* Start the dump of a graph.  */
+static void
+start_graph_dump (FILE *fp)
+{
+  fputs ("digraph \"\" {\n"
+	 "overlap=false;\n",
+	 fp);
+}
 
-/* Similar as clean_dump_file, but this time for graph output files.  */
+/* End the dump of a graph.  */
+static void
+end_graph_dump (FILE *fp)
+{
+  fputs ("}\n", fp);
+}
 
+/* Similar as clean_dump_file, but this time for graph output files.  */
 void
 clean_graph_dump_file (const char *base)
 {
-  size_t namelen = strlen (base);
-  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
-  char *buf = XALLOCAVEC (char, namelen + extlen);
-  FILE *fp;
-
-  memcpy (buf, base, namelen);
-  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
-
-  fp = fopen (buf, "w");
-
-  if (fp == NULL)
-    fatal_error ("can%'t open %s: %m", buf);
-
-  gcc_assert (graph_dump_format == vcg);
-  fputs ("graph: {\nport_sharing: no\n", fp);
-
+  FILE *fp = open_graph_file (base, "w");
+  start_graph_dump (fp);
   fclose (fp);
 }
 
@@ -420,19 +267,7 @@ clean_graph_dump_file (const char *base)
 void
 finish_graph_dump_file (const char *base)
 {
-  size_t namelen = strlen (base);
-  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
-  char *buf = XALLOCAVEC (char, namelen + extlen);
-  FILE *fp;
-
-  memcpy (buf, base, namelen);
-  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
-
-  fp = fopen (buf, "a");
-  if (fp != NULL)
-    {
-      gcc_assert (graph_dump_format == vcg);
-      fputs ("}\n", fp);
-      fclose (fp);
-    }
+  FILE *fp = open_graph_file (base, "a");
+  end_graph_dump (fp);
+  fclose (fp);
 }
Index: graph.h
===================================================================
--- graph.h	(revision 193650)
+++ graph.h	(working copy)
@@ -20,7 +20,7 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_GRAPH_H
 #define GCC_GRAPH_H
 
-extern void print_rtl_graph_with_bb (const char *, rtx);
+extern void print_rtl_graph_with_bb (const char *, tree);
 extern void clean_graph_dump_file (const char *);
 extern void finish_graph_dump_file (const char *);
 
Index: passes.c
===================================================================
--- passes.c	(revision 193650)
+++ passes.c	(working copy)
@@ -239,19 +239,18 @@ finish_optimization_passes (void)
     {
       dump_start (pass_profile.pass.static_pass_number, NULL);
       print_combine_total_stats ();
-      dump_finish (pass_combine.pass.static_pass_number);
+      dump_finish (pass_profile.pass.static_pass_number);
     }
 
   /* Do whatever is necessary to finish printing the graphs.  */
-  if (graph_dump_format != no_graph)
-    for (i = TDI_end; (dfi = get_dump_file_info (i)) != NULL; ++i)
-      if (dump_initialized_p (i)
-	  && (dfi->pflags & TDF_GRAPH) != 0
-	  && (name = get_dump_file_name (i)) != NULL)
-	{
-	  finish_graph_dump_file (name);
-	  free (name);
-	}
+  for (i = TDI_end; (dfi = get_dump_file_info (i)) != NULL; ++i)
+    if (dump_initialized_p (i)
+	&& (dfi->pflags & TDF_GRAPH) != 0
+	&& (name = get_dump_file_name (i)) != NULL)
+      {
+	finish_graph_dump_file (name);
+	free (name);
+      }
 
   timevar_pop (TV_DUMP);
 }
@@ -1775,18 +1774,16 @@ execute_function_dump (void *data ATTRIBUTE_UNUSED
       if (cfun->curr_properties & PROP_trees)
         dump_function_to_file (current_function_decl, dump_file, dump_flags);
       else
-	{
-	  print_rtl_with_bb (dump_file, get_insns (), dump_flags);
+	print_rtl_with_bb (dump_file, get_insns (), dump_flags);
 
-	  if ((cfun->curr_properties & PROP_cfg)
-	      && graph_dump_format != no_graph
-	      && (dump_flags & TDF_GRAPH))
-	    print_rtl_graph_with_bb (dump_file_name, get_insns ());
-	}
-
       /* Flush the file.  If verification fails, we won't be able to
 	 close the file before aborting.  */
       fflush (dump_file);
+
+      if ((cfun->curr_properties & PROP_cfg)
+	  && (cfun->curr_properties & PROP_rtl)
+	  && (dump_flags & TDF_GRAPH))
+	print_rtl_graph_with_bb (dump_file_name, cfun->decl);
     }
 }
 
@@ -2336,13 +2333,11 @@ execute_one_pass (struct opt_pass *pass)
 
   if (initializing_dump
       && dump_file
-      && graph_dump_format != no_graph
+      && (dump_flags & TDF_GRAPH)
       && cfun
       && (cfun->curr_properties & (PROP_cfg | PROP_rtl))
 	  == (PROP_cfg | PROP_rtl))
     {
-      get_dump_file_info (pass->static_pass_number)->pflags |= TDF_GRAPH;
-      dump_flags |= TDF_GRAPH;
       clean_graph_dump_file (dump_file_name);
     }
 
Index: ddg.c
===================================================================
--- ddg.c	(revision 193650)
+++ ddg.c	(working copy)
@@ -753,7 +753,7 @@ print_ddg (FILE *file, ddg_ptr g)
 }
 
 /* Print the given DDG in VCG format.  */
-void
+DEBUG_FUNCTION void
 vcg_print_ddg (FILE *file, ddg_ptr g)
 {
   int src_cuid;
Index: toplev.c
===================================================================
--- toplev.c	(revision 193650)
+++ toplev.c	(working copy)
@@ -49,7 +49,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "basic-block.h"
 #include "intl.h"
 #include "ggc.h"
-#include "graph.h"
 #include "regs.h"
 #include "timevar.h"
 #include "diagnostic.h"
Index: tree-optimize.c
===================================================================
--- tree-optimize.c	(revision 193650)
+++ tree-optimize.c	(working copy)
@@ -38,7 +38,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "ggc.h"
 #include "cgraph.h"
-#include "graph.h"
 #include "cfgloop.h"
 #include "except.h"
 #include "plugin.h"
Index: testsuite/gcc.dg/20050811-1.c
===================================================================
--- testsuite/gcc.dg/20050811-1.c	(revision 193650)
+++ testsuite/gcc.dg/20050811-1.c	(working copy)
@@ -1,6 +1,6 @@
-/* Test whether -dv -fdump-rtl-all doesn't crash.  */
+/* Test whether -fdump-rtl-all-graph doesn't crash.  */
 /* { dg-do compile } */
-/* { dg-options "-O2 -dv -fdump-rtl-all" } */
+/* { dg-options "-O2 -fdump-rtl-all-graph" } */
 
 int foo (void)
 {
Index: testsuite/gcc.dg/pr37858.c
===================================================================
--- testsuite/gcc.dg/pr37858.c	(revision 193650)
+++ testsuite/gcc.dg/pr37858.c	(working copy)
@@ -1,6 +1,7 @@
 /* PR middle-end/37858 */
+/* ??? With -dv removed, this test is a bit silly.  */
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-ipa-early_local_cleanups -dv" } */
+/* { dg-options "-O2 -fdump-ipa-early_local_cleanups" } */
 
 int
 main (void)

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-12-03 11:05 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-23  9:47 [patch] Rework RTL CFG graph dumping to dump DOT format Steven Bosscher
2012-11-26 15:46 ` Richard Biener
2012-11-26 15:54   ` Steven Bosscher
2012-11-26 16:13     ` Richard Biener
2012-12-01 13:24   ` Steven Bosscher
2012-12-01 17:41     ` Steven Bosscher
2012-12-03 11:05       ` Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).