From cf0bd99ba618dd85777e497da382086ff728a863 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 28 Sep 2016 21:57:03 -0400
Subject: [PATCH 02/43] COMMITTED: Machine-readable RTL dumps:
 print_rtx_function

This patch adds a new function, print_rtx_function, intended for use
for generating function dumps suitable for parsing by the RTL frontend,
but also intended to be human-readable, and human-authorable.

I put the function in its own file (rather than print-rtl.c) to avoid
having to recompile all the gen* files etc every time the format is
tweaked.

It's not enough to simply record the insn chain: we need to also capture
the CFG and various other state.

It's possible to reconstruct the CFG based on jump instructions when we're
in "cfgrtl" mode (https://gcc.gnu.org/wiki/cfglayout_mode) but not when
in "cfglayout" mode - in the latter,  unconditional jumps are represented
purely by edges in the CFG, not via jump instructions.  So it seems best
to directly capture the CFG.  I plan to keep the CFG-reconstruction code,
so that the CFG information can be optional, to make it easier to
write interesting test cases by hand (for cfgrtl passes).

Some other state needs to be captured.  I know that we need to at least
capture crtl->return_rtx.  The reason for this is that in the normal case
of expanding gimple, this is set inside assign_parms via non-trivial
target-specific logic.  We don't want to rerun assign_parms when loading
a dump as it could insert new insns.  In theory we could rerun parts of
this logic, but it seems simplest to have the dump record the decisions
that were made by assign_parms.  (if crtl->return_rtx is not set, then
df subtly changes behavior, e.g on x86_64 "ax" is not recognized as
used at the exit block).

Nothing in the tree actually uses the new dump function; you (currently)
have to call it manually from the debugger.  We could start using this
function in various pass dumps - though that would obviously
run the risk of affecting dump-scanning in the DejaGnu test suite, so
I'm leaving that as followup work.

The new dump format looks a lot like the existing insn chain dumps:
Here's an example dump (from x86_64).  I put the insn chain at the
top, with the other data coming after it, since GCC developers are
used to seeing the insn chain.  The dump uses indentation and
comments to make it easier for humans to grok.

 (function "times_two"
   (insn-chain
     (note 1 0 4 (nil) NOTE_INSN_DELETED)
     (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
     (insn 2 4 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
                         (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
                 (reg:SI 5 di [ i ])) t.c:2 -1
              (nil))
     (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
     (insn 6 3 7 2 (set (reg:SI 89)
                 (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
                         (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) t.c:3 -1
              (nil))
     (insn 7 6 10 2 (parallel [
                     (set (reg:SI 87 [ _2 ])
                         (ashift:SI (reg:SI 89)
                             (const_int 1 [0x1])))
                     (clobber (reg:CC 17 flags))
                 ]) t.c:3 -1
              (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
                             (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
                     (const_int 1 [0x1]))
                 (nil)))
     (insn 10 7 14 2 (set (reg:SI 88 [ <retval> ])
                 (reg:SI 87 [ _2 ])) t.c:3 -1
              (nil))
     (insn 14 10 15 2 (set (reg/i:SI 0 ax)
                 (reg:SI 88 [ <retval> ])) t.c:4 -1
              (nil))
     (insn 15 14 0 2 (use (reg/i:SI 0 ax)) t.c:4 -1
              (nil))
   ) ;; insn-chain
   (cfg
     (bb 0
       (edge 0 2 (flags 0x1))
     ) ;; bb
     (bb 2
       (edge 2 1 (flags 0x1))
     ) ;; bb
     (bb 1
     ) ;; bb
   ) ;; cfg
   (crtl
     (return_rtx
       (reg/i:SI 0 ax)
     ) ;; return_rtx
   ) ;; crtl
 ) ;; function "times_two"

I anticipate the format gaining extra fields, but I want to nail
down the basic ideas and structure a little before I rewrite the
RTL frontend to use it, hence this patch.

OK for trunk?

gcc/ChangeLog:
	* Makefile.in (OBJS): Add print-rtl-function.o.
	* print-rtl-function.c: New file.
	* print-rtl.h (print_rtx_function): New decl.
---
 gcc/Makefile.in          |   1 +
 gcc/print-rtl-function.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++
 gcc/print-rtl.h          |   2 +
 3 files changed, 134 insertions(+)
 create mode 100644 gcc/print-rtl-function.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index ff12908..15c48bc 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1405,6 +1405,7 @@ OBJS = \
 	postreload.o \
 	predict.o \
 	print-rtl.o \
+	print-rtl-function.o \
 	print-tree.o \
 	profile.o \
 	real.o \
diff --git a/gcc/print-rtl-function.c b/gcc/print-rtl-function.c
new file mode 100644
index 0000000..c4b99c0
--- /dev/null
+++ b/gcc/print-rtl-function.c
@@ -0,0 +1,131 @@
+/* Print RTL functions for GCC.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+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
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "alias.h"
+#include "tree.h"
+#include "cfg.h"
+#include "flags.h"
+#include "predict.h"
+#include "function.h"
+#include "basic-block.h"
+#include "print-rtl.h"
+#include "langhooks.h"
+#include "emit-rtl.h"
+
+/* Write FN to OUTFILE in a form suitable for parsing, with indentation
+   and comments to make the structure easy for a human to grok.
+
+   Example output:
+
+     (function "times_two"
+       (insn-chain
+	 (note 1 0 4 (nil) NOTE_INSN_DELETED)
+	 (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+	 (insn 2 4 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+			     (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+		     (reg:SI 5 di [ i ])) t.c:2 -1
+		  (nil))
+	 (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
+	 (insn 6 3 7 2 (set (reg:SI 89)
+		     (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+			     (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) t.c:3 -1
+		  (nil))
+	 (insn 7 6 10 2 (parallel [
+			 (set (reg:SI 87 [ _2 ])
+			     (ashift:SI (reg:SI 89)
+				 (const_int 1 [0x1])))
+			 (clobber (reg:CC 17 flags))
+		     ]) t.c:3 -1
+		  (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+				 (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+			 (const_int 1 [0x1]))
+		     (nil)))
+	 (insn 10 7 14 2 (set (reg:SI 88 [ <retval> ])
+		     (reg:SI 87 [ _2 ])) t.c:3 -1
+		  (nil))
+	 (insn 14 10 15 2 (set (reg/i:SI 0 ax)
+		     (reg:SI 88 [ <retval> ])) t.c:4 -1
+		  (nil))
+	 (insn 15 14 0 2 (use (reg/i:SI 0 ax)) t.c:4 -1
+		  (nil))
+       ) ;; insn-chain
+       (cfg
+	 (bb 0
+	   (edge 0 2 (flags 0x1))
+	 ) ;; bb
+	 (bb 2
+	   (edge 2 1 (flags 0x1))
+	 ) ;; bb
+	 (bb 1
+	 ) ;; bb
+       ) ;; cfg
+       (crtl
+	 (return_rtx
+	   (reg/i:SI 0 ax)
+	 ) ;; return_rtx
+       ) ;; crtl
+     ) ;; function "times_two"
+*/
+
+DEBUG_FUNCTION void
+print_rtx_function (FILE *outfile, function *fn)
+{
+  tree fdecl = fn->decl;
+
+  const char *dname = lang_hooks.decl_printable_name (fdecl, 2);
+
+  fprintf (outfile, "(function \"%s\"\n", dname);
+
+  /* The instruction chain.  */
+  fprintf (outfile, "  (insn-chain\n");
+  for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    print_rtl_single_with_indent (outfile, insn, 4);
+  fprintf (outfile, "  ) ;; insn-chain\n");
+
+  /* The CFG.  */
+  fprintf (outfile, "  (cfg\n");
+  {
+    basic_block bb;
+    FOR_ALL_BB_FN (bb, fn)
+      {
+	fprintf (outfile, "    (bb %i\n", bb->index);
+	edge e;
+	edge_iterator ei;
+	FOR_EACH_EDGE (e, ei, bb->succs)
+	  fprintf (outfile, "      (edge %i %i (flags 0x%x))\n",
+		   e->src->index, e->dest->index, e->flags);
+	fprintf (outfile, "    ) ;; bb\n");
+      }
+  }
+  fprintf (outfile, "  ) ;; cfg\n");
+
+  /* Additional RTL state.  */
+  fprintf (outfile, "  (crtl\n");
+  fprintf (outfile, "    (return_rtx \n");
+  print_rtl_single_with_indent (outfile, crtl->return_rtx, 6);
+  fprintf (outfile, "    ) ;; return_rtx\n");
+  fprintf (outfile, "  ) ;; crtl\n");
+
+  fprintf (outfile, ") ;; function \"%s\"\n", dname);
+}
diff --git a/gcc/print-rtl.h b/gcc/print-rtl.h
index e585a63..9cad683 100644
--- a/gcc/print-rtl.h
+++ b/gcc/print-rtl.h
@@ -36,4 +36,6 @@ extern void print_insn (pretty_printer *pp, const rtx_insn *x, int verbose);
 extern void rtl_dump_bb_for_graph (pretty_printer *, basic_block);
 extern const char *str_pattern_slim (const_rtx);
 
+extern void print_rtx_function (FILE *file, function *fn);
+
 #endif  // GCC_PRINT_RTL_H
-- 
1.8.5.3

