public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 08/16] (partially-approved): Introduce selftest::locate_file
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
@ 2016-10-05 15:44 ` David Malcolm
  2016-10-05 16:10   ` Bernd Schmidt
  2016-10-05 15:44 ` [PATCH 07/16] read-md: add some helper functions David Malcolm
                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:44 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Jeff:
> I do think we should go ahead and plan for a target subdirectory.  With
> that added, this should be OK once dependencies are in.

Loading RTL dumps from files rather than embedding them as strings
in the source requires a way to locate the relevant files.

This patch adds a selftest::locate_file function for locating such
files, relative to "$(SRCDIR)/gcc/testsuite/selftests".  This is
done via a new argument to -fself-test, which supplies the current
value of "$(SRCDIR)/gcc" to cc1.

I chose "$(SRCDIR)/gcc/testsuite/selftests", so as to be below
gcc/testsuite, but not below any of the existing DejaGnu subdirectories,
to avoid selftest-specific files from being picked up by .exp globbing
patterns.

(Depends on the approved-when-needed
  "[PATCH 2/9] Add selftest::read_file"
    https://gcc.gnu.org/ml/gcc-patches/2016-09/msg00476.html ).

gcc/ChangeLog:
	* Makefile.in (s-selftest) Add $(srcdir) as an argument of
	-fself-test.
	(selftest-gdb): Likewise.
	(selftest-valgrind): Likewise.
	* common.opt (fself-test): Rename to...
	(fself-test=): ...this, documenting the meaning of the argument.
	* selftest-run-tests.c: Include "options.h".
	(selftest::run_tests): Initialize selftest::path_to_src_gcc from
	flag_self_test.
	* selftest.c (selftest::path_to_src_gcc): New global.
	(selftest::locate_file): New function.
	(selftest::test_locate_file): New function.
	(selftest::selftest_c_tests): Call test_locate_file.
	* selftest.h (selftest::locate_file): New decl.
	(selftest::path_to_src_gcc): New decl.

gcc/testsuite/ChangeLog:
	* gcc.dg/cpp/pr71591.c: Add a fake value for the argument of
	-fself-test.
	* selftests/example.txt: New file.
---
 gcc/Makefile.in                     |  7 ++++---
 gcc/common.opt                      |  6 +++---
 gcc/selftest-run-tests.c            |  7 +++++++
 gcc/selftest.c                      | 28 ++++++++++++++++++++++++++++
 gcc/selftest.h                      | 10 ++++++++++
 gcc/testsuite/gcc.dg/cpp/pr71591.c  |  2 +-
 gcc/testsuite/selftests/example.txt |  1 +
 7 files changed, 54 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/selftests/example.txt

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 15c48bc..4b50f0b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1883,18 +1883,19 @@ rest.cross: specs
 .PHONY: selftest
 selftest: s-selftest
 s-selftest: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
-	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test
+	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test=$(srcdir)
 	$(STAMP) $@
 
 # Convenience method for running selftests under gdb:
 .PHONY: selftest-gdb
 selftest-gdb: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
-	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test -wrapper gdb,--args
+	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test=$(srcdir) \
+	  -wrapper gdb,--args
 
 # Convenience method for running selftests under valgrind:
 .PHONY: selftest-valgrind
 selftest-valgrind: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
-	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test \
+	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test=$(srcdir) \
 	  -wrapper valgrind,--leak-check=full
 
 # Recompile all the language-independent object files.
diff --git a/gcc/common.opt b/gcc/common.opt
index 3425c19..c3cf4c2 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2106,9 +2106,9 @@ fselective-scheduling2
 Common Report Var(flag_selective_scheduling2) Optimization
 Run selective scheduling after reload.
 
-fself-test
-Common Undocumented Var(flag_self_test)
-Run self-tests.
+fself-test=
+Common Undocumented Joined Var(flag_self_test)
+Run self-tests, using the given path to locate test files.
 
 fsel-sched-pipelining
 Common Report Var(flag_sel_sched_pipelining) Init(0) Optimization
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 54a9b0f..ecc3d71 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "selftest.h"
 #include "tree.h"
 #include "langhooks.h"
+#include "options.h"
 
 /* This function needed to be split out from selftest.c as it references
    tests from the whole source tree, and so is within
@@ -37,6 +38,12 @@ along with GCC; see the file COPYING3.  If not see
 void
 selftest::run_tests ()
 {
+  /* Makefile.in has -fself-test=$(srcdir), so that flag_self_test
+     contains the path to the "gcc" subdirectory of the source tree
+     (without a trailing slash).  Copy it up to path_to_src_gcc, to
+     avoid selftest.c depending on option-handling.  */
+  path_to_src_gcc = flag_self_test;
+
   long start_time = get_run_time ();
 
   /* Run all the tests, in hand-coded order of (approximate) dependencies:
diff --git a/gcc/selftest.c b/gcc/selftest.c
index cf7031f..2a481ad 100644
--- a/gcc/selftest.c
+++ b/gcc/selftest.c
@@ -198,6 +198,21 @@ read_file (const location &loc, const char *path)
   return result;
 }
 
+/* The path of SRCDIR/gcc.  */
+
+const char *path_to_src_gcc = NULL;
+
+/* Convert a path relative to SRCDIR/gcc/testsuite/selftests
+   to a real path (either absolute, or relative to pwd).
+   The result should be freed by the caller.  */
+
+char *
+locate_file (const char *name)
+{
+  ASSERT_NE (NULL, path_to_src_gcc);
+  return concat (path_to_src_gcc, "/testsuite/selftests/", name, NULL);
+}
+
 /* Selftests for the selftest system itself.  */
 
 /* Sanity-check the ASSERT_ macros with various passing cases.  */
@@ -240,6 +255,18 @@ test_read_file ()
   free (buf);
 }
 
+/* Verify locate_file (and read_file).  */
+
+static void
+test_locate_file ()
+{
+  char *path = locate_file ("example.txt");
+  char *buf = read_file (SELFTEST_LOCATION, path);
+  ASSERT_STREQ ("example of a selftest file\n", buf);
+  free (buf);
+  free (path);
+}
+
 /* Run all of the selftests within this file.  */
 
 void
@@ -248,6 +275,7 @@ selftest_c_tests ()
   test_assertions ();
   test_named_temp_file ();
   test_read_file ();
+  test_locate_file ();
 }
 
 } // namespace selftest
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 86ad14c..8b9c007 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -187,6 +187,16 @@ class temp_override
 
 extern void forcibly_ggc_collect ();
 
+/* Convert a path relative to SRCDIR/gcc/testsuite/selftests
+   to a real path (either absolute, or relative to pwd).
+   The result should be freed by the caller.  */
+
+extern char *locate_file (const char *path);
+
+/* The path of SRCDIR/gcc.  */
+
+extern const char *path_to_src_gcc;
+
 /* Declarations for specific families of tests (by source file), in
    alphabetical order.  */
 extern void bitmap_c_tests ();
diff --git a/gcc/testsuite/gcc.dg/cpp/pr71591.c b/gcc/testsuite/gcc.dg/cpp/pr71591.c
index e92cb52..0e3d7b1 100644
--- a/gcc/testsuite/gcc.dg/cpp/pr71591.c
+++ b/gcc/testsuite/gcc.dg/cpp/pr71591.c
@@ -1,5 +1,5 @@
 /* PR rtl-optimization/71591 */
 /* { dg-do preprocess } */
-/* { dg-options "-fself-test" } */
+/* { dg-options "-fself-test=fake-value" } */
 
 /* { dg-message "self-tests incompatible with -E" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/selftests/example.txt b/gcc/testsuite/selftests/example.txt
new file mode 100644
index 0000000..fbfaa33
--- /dev/null
+++ b/gcc/testsuite/selftests/example.txt
@@ -0,0 +1 @@
+example of a selftest file
-- 
1.8.5.3

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

* [PATCH 07/16] read-md: add some helper functions
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
  2016-10-05 15:44 ` [PATCH 08/16] (partially-approved): Introduce selftest::locate_file David Malcolm
@ 2016-10-05 15:44 ` David Malcolm
  2016-10-05 15:57   ` Bernd Schmidt
  2016-10-05 15:44 ` [PATCH 11/16] df selftests (v3) David Malcolm
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:44 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Add some functions for use by the RTL frontend.

gcc/ChangeLog:
	* read-md.c (require_char): New function.
	(require_word_ws): New function.
	(peek_char): New function.
	* read-md.h (peek_char): New decl.
	(require_char): New decl.
	(require_word_ws): New decl.
---
 gcc/read-md.c | 31 +++++++++++++++++++++++++++++++
 gcc/read-md.h |  4 ++++
 2 files changed, 35 insertions(+)

diff --git a/gcc/read-md.c b/gcc/read-md.c
index 1a13916..1bbf408 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -364,6 +364,16 @@ read_skip_spaces (void)
     }
 }
 
+/* Consume the next character, issuing a fatal error if it is not
+   EXPECTED.  */
+
+void require_char (char expected)
+{
+  int ch = read_char ();
+  if (ch != expected)
+    fatal_expected_char (expected, ch);
+}
+
 /* Consume any whitespace, then consume the next non-whitespace
    character, issuing a fatal error if it is not EXPECTED.  */
 
@@ -375,6 +385,17 @@ require_char_ws (char expected)
     fatal_expected_char (expected, ch);
 }
 
+/* Consume any whitespace, then consume the next word (as per read_name),
+   issuing a fatal error if it is not EXPECTED.  */
+
+void require_word_ws (const char *expected)
+{
+  struct md_name name;
+  read_name (&name);
+  if (strcmp (name.string, expected))
+    fatal_with_file_and_line ("missing '%s'", expected);
+}
+
 /* Read the next character from the file.  */
 
 int
@@ -410,6 +431,16 @@ rtx_reader::unread_char (int ch)
   ungetc (ch, m_read_md_file);
 }
 
+/* Peek at the next character from the file without consuming it.  */
+
+int
+peek_char (void)
+{
+  int ch = read_char ();
+  unread_char (ch);
+  return ch;
+}
+
 /* Read an rtx code name into NAME.  It is terminated by any of the
    punctuation chars of rtx printed syntax.  */
 
diff --git a/gcc/read-md.h b/gcc/read-md.h
index a74cc72..88d2d4f 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -194,6 +194,8 @@ unread_char (int ch)
   rtx_reader_ptr->unread_char (ch);
 }
 
+extern int peek_char (void);
+
 extern hashval_t leading_string_hash (const void *);
 extern int leading_string_eq_p (const void *, const void *);
 extern void copy_md_ptr_loc (const void *, const void *);
@@ -209,7 +211,9 @@ extern void fatal_with_file_and_line (const char *, ...)
   ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
 extern void fatal_expected_char (int, int) ATTRIBUTE_NORETURN;
 extern int read_skip_spaces (void);
+extern void require_char (char expected);
 extern void require_char_ws (char expected);
+extern void require_word_ws (const char *expected);
 extern void read_name (struct md_name *);
 extern char *read_quoted_string (void);
 extern char *read_string (int);
-- 
1.8.5.3

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

* [PATCH 11/16] df selftests (v3)
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
  2016-10-05 15:44 ` [PATCH 08/16] (partially-approved): Introduce selftest::locate_file David Malcolm
  2016-10-05 15:44 ` [PATCH 07/16] read-md: add some helper functions David Malcolm
@ 2016-10-05 15:44 ` David Malcolm
  2016-10-05 15:44 ` [PATCH 01/16] read-md.c: Add various cleanups to ~rtx_reader David Malcolm
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:44 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Changes since v2:
* moved dump from a string literal to an external file
* update for addition of selftest::location to rtl_dump_test
* remove debug prints

gcc/ChangeLog:
	* df-core.c: Include selftest.h and selftest-rtl.h.
	(selftest::dataflow_test::dataflow_test): New ctor.
	(selftest::dataflow_test::~dataflow_test): New dtor.
	(selftest::test_df_single_set): New function.
	(selftest::df_core_c_tests): New function.
	* selftest-run-tests.c (selftest::run_tests): Call it.
	* selftest.h (selftest::df_core_c_tests): New decl.

gcc/testsuite/ChangeLog:
	* selftests/single-set.rtl: New file.
---
 gcc/df-core.c                          | 73 ++++++++++++++++++++++++++++++++++
 gcc/selftest-run-tests.c               |  1 +
 gcc/selftest.h                         |  1 +
 gcc/testsuite/selftests/single-set.rtl |  5 +++
 4 files changed, 80 insertions(+)
 create mode 100644 gcc/testsuite/selftests/single-set.rtl

diff --git a/gcc/df-core.c b/gcc/df-core.c
index e531d58..2c8ccba 100644
--- a/gcc/df-core.c
+++ b/gcc/df-core.c
@@ -384,6 +384,8 @@ are write-only operations.
 #include "cfganal.h"
 #include "tree-pass.h"
 #include "cfgloop.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
 
 static void *df_get_bb_info (struct dataflow *, unsigned int);
 static void df_set_bb_info (struct dataflow *, unsigned int, void *);
@@ -2482,3 +2484,74 @@ debug_df_chain (struct df_link *link)
   df_chain_dump (link, stderr);
   fputc ('\n', stderr);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* dataflow_test's constructor.  Initialize df.  */
+
+dataflow_test::dataflow_test ()
+{
+  rest_of_handle_df_initialize ();
+}
+
+/* dataflow_test's destructor.  Clean up df.  */
+
+dataflow_test::~dataflow_test ()
+{
+  rest_of_handle_df_finish ();
+}
+
+/* Verify df_note on a trivial function.  */
+
+void
+test_df_single_set ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("single-set.rtl"));
+
+  dataflow_test dftest;
+
+  df_note_add_problem ();
+  df_analyze ();
+  df_finish_pass (false);
+
+  rtx_insn *insn = get_insn_by_uid (1);
+
+  ASSERT_NE (NULL, REG_NOTES (insn));
+  rtx_expr_list *note0 = as_a <rtx_expr_list *> (REG_NOTES (insn));
+
+  rtx_expr_list *note1 = note0->next ();
+  ASSERT_NE (NULL, note1);
+
+  ASSERT_EQ (NULL, note1->next ());
+
+  ASSERT_EQ (SET_SRC (PATTERN (insn)), note0->element ());
+  ASSERT_EQ (REG_DEAD, REG_NOTE_KIND (note0));
+
+  ASSERT_EQ (SET_DEST (PATTERN (insn)), note1->element ());
+  ASSERT_EQ (REG_UNUSED, REG_NOTE_KIND (note1));
+
+  struct df_lr_bb_info *bb_info = df_lr_get_bb_info (2);
+  ASSERT_NE (NULL, bb_info);
+
+  /* "r100 = r101;" so we should have a use of r101.  */
+  ASSERT_FALSE (bitmap_bit_p (&bb_info->use, t.effective_regno (100)));
+  ASSERT_TRUE (bitmap_bit_p (&bb_info->use, t.effective_regno (101)));
+
+  /* ...and a def of r100.  */
+  ASSERT_TRUE (bitmap_bit_p (&bb_info->def, t.effective_regno (100)));
+  ASSERT_FALSE (bitmap_bit_p (&bb_info->def, t.effective_regno (101)));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+df_core_c_tests ()
+{
+  test_df_single_set ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 1dce665..5c95aaa 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -71,6 +71,7 @@ selftest::run_tests ()
   gimple_c_tests ();
   rtl_tests_c_tests ();
   read_rtl_function_c_tests ();
+  df_core_c_tests ();
 
   /* Higher-level tests, or for components that other selftests don't
      rely on.  */
diff --git a/gcc/selftest.h b/gcc/selftest.h
index ae39101..0033942 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -200,6 +200,7 @@ extern const char *path_to_src_gcc;
 /* Declarations for specific families of tests (by source file), in
    alphabetical order.  */
 extern void bitmap_c_tests ();
+extern void df_core_c_tests ();
 extern void diagnostic_c_tests ();
 extern void diagnostic_show_locus_c_tests ();
 extern void edit_context_c_tests ();
diff --git a/gcc/testsuite/selftests/single-set.rtl b/gcc/testsuite/selftests/single-set.rtl
new file mode 100644
index 0000000..d72015f
--- /dev/null
+++ b/gcc/testsuite/selftests/single-set.rtl
@@ -0,0 +1,5 @@
+(function "test"
+  (insn-chain
+     (insn 1 0 0 2 (set (reg:SI 100) (reg:SI 101)) -1 (nil))
+  ) ;; insn-chain
+) ;; function
-- 
1.8.5.3

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

* [PATCH 01/16] read-md.c: Add various cleanups to ~rtx_reader
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (2 preceding siblings ...)
  2016-10-05 15:44 ` [PATCH 11/16] df selftests (v3) David Malcolm
@ 2016-10-05 15:44 ` David Malcolm
  2016-10-05 15:51   ` Bernd Schmidt
  2016-10-05 15:45 ` [PATCH 02/16] (approved) Add selftest::read_file David Malcolm
                   ` (11 subsequent siblings)
  15 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:44 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Various global data items relating to reading .md files are
currently initialized in rtx_reader::read_md_files, and are
not cleaned up.

The selftests for the RTL frontend require supporting multiple
reader instances being alive one after another in-process, so
this lack of cleanup would become a leak.

To fix this, this patch moves these initializations to the
rtx_reader constructor, and adds matching cleanups to the destructor,
along with a cleanup of m_base_dir.

gcc/ChangeLog:
	* read-md.c (rtx_reader::rtx_reader): Move initializations
	of various global data from rtx_reader::read_md_files to here.
	(rtx_reader::~rtx_reader): Clean up m_base_dir, and various
	global data.
	(rtx_reader::read_md_files): Move initializations of various
	global data from here to the ctor.
---
 gcc/read-md.c | 49 +++++++++++++++++++++++++++++++++++--------------
 1 file changed, 35 insertions(+), 14 deletions(-)

diff --git a/gcc/read-md.c b/gcc/read-md.c
index e158be5..1a13916 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -925,12 +925,47 @@ rtx_reader::rtx_reader ()
 {
   /* Set the global singleton pointer.  */
   rtx_reader_ptr = this;
+
+  /* Initialize global data.  */
+  obstack_init (&string_obstack);
+  ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
+  obstack_init (&ptr_loc_obstack);
+  joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
+  obstack_init (&joined_conditions_obstack);
+  md_constants = htab_create (31, leading_string_hash,
+			      leading_string_eq_p, (htab_del) 0);
+  enum_types = htab_create (31, leading_string_hash,
+			    leading_string_eq_p, (htab_del) 0);
+
+  /* Unlock the stdio streams.  */
+  unlock_std_streams ();
 }
 
 /* rtx_reader's destructor.  */
 
 rtx_reader::~rtx_reader ()
 {
+  free (m_base_dir);
+
+  /* Clean up global data.  */
+  htab_delete (enum_types);
+  enum_types = NULL;
+
+  htab_delete (md_constants);
+  md_constants = NULL;
+
+  obstack_free (&joined_conditions_obstack, NULL);
+
+  htab_delete (joined_conditions);
+  joined_conditions = NULL;
+
+  obstack_free (&ptr_loc_obstack, NULL);
+
+  htab_delete (ptr_locs);
+  ptr_locs = NULL;
+
+  obstack_free (&string_obstack, NULL);
+
   /* Clear the global singleton pointer.  */
   rtx_reader_ptr = NULL;
 }
@@ -1105,20 +1140,6 @@ rtx_reader::read_md_files (int argc, const char **argv,
   bool already_read_stdin;
   int num_files;
 
-  /* Initialize global data.  */
-  obstack_init (&string_obstack);
-  ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
-  obstack_init (&ptr_loc_obstack);
-  joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
-  obstack_init (&joined_conditions_obstack);
-  md_constants = htab_create (31, leading_string_hash,
-			      leading_string_eq_p, (htab_del) 0);
-  enum_types = htab_create (31, leading_string_hash,
-			    leading_string_eq_p, (htab_del) 0);
-
-  /* Unlock the stdio streams.  */
-  unlock_std_streams ();
-
   /* First we loop over all the options.  */
   for (i = 1; i < argc; i++)
     if (argv[i][0] == '-')
-- 
1.8.5.3

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

* [PATCH 00/16] RTL frontend (v3)
@ 2016-10-05 15:44 David Malcolm
  2016-10-05 15:44 ` [PATCH 08/16] (partially-approved): Introduce selftest::locate_file David Malcolm
                   ` (15 more replies)
  0 siblings, 16 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:44 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

This patch kit is v3 of the RTL frontend.  For reference, the earlier
versions were:

v1 (2016-05-04):
  "[PATCH 0/4] RFC: RTL frontend"
    https://gcc.gnu.org/ml/gcc-patches/2016-05/msg00352.html
  
v2 (2016-09-08):
  "[PATCH 0/9] RFC: selftests based on RTL dumps"
    https://gcc.gnu.org/ml/gcc-patches/2016-09/msg00483.html

The patch kit is based on top of r240740 (2016-10-04).

What's new in v3:

* The input file format is now the output format of the recently-added
  "print_rtx_function", which emits CFG and crtl information.  The
  code can now parse that new information and reconstruct it.
  The CFG info is optional when parsing, to make it easier to
  edit and create input RTL "by hand".
  (patch 10 in the kit).

* This version adds back in the "rtl1" frontend, and "rtl.dg" in
  the testsuite, capable of running individual passes on RTL dumps.    
  (patch 15 in the kit).

* Added an rtl-frontend.texi to the gccint docs (patch 15), which
  contains additional high-level information.

* This version also implements Richi's idea of using the C frontend:
  tagging C functions with "__RTL", and then being able to supply an
  RTL dump as the body of the function.  This allows for more
  interesting decls and types in test cases.
  (patch 16 in the kit).

  There are thus three forms of dump-reading in this kit:
    (a) selftests that read a .rtl file,
    (b) rtl.dg tests that read a .rtl file, and
    (c) rtl.dg tests that read a .c file
  all built on top of class function_reader (and thus sharing most of
  their code).

* Previously all of the various dumps in selftests were string
  fragments in the pass .c files; they've now been moved to .rtl files
  and .c files below the "gcc/testsuite" subdirectory (to
  "gcc/testsuite/selftest" and to "gcc/testsuite/rtl.dg").  Tests
  have been moved to target-specific subdirectories where appropriate.

* I've split out lots of preliminary material from the bigger patches
  (hence this is a 16-patch kit, but hopefully this is easier as a whole
  to digest).

* Rewrote how pseudos get renumbered (see rtl-frontend.texi in patch 15
  for details).

* Much of the unpleasantness of reading the print_rtx format has been
  reduced and contained, by moving the special-case handling of operand
  parsing to read-rtl-function.c, and splitting it out into a collection
  of short routines, rather than one big one.

* I dropped source locations from the parser for now, for the sake of
  simplicity (which means dropping the roundtrip.exp part of rtl.dg).

* Fixed an auto-dependency problem that prevented bootstrap.

* Added a run-one-rtl-pass.c/h (patch 15), to encapsulate the hacks
  that appear to be necessary to do this (for rtl1 and for
  cc1's __RTL mode).

* Added a prototype of an RTL interpreter, a kind of "valgrind for RTL"
  (patch 14) to show how this work could enable such a thing.  This
  patch is more just an idea than a real implementation at this point.

* More test cases

The patch kit (as a whole) bootstraps and passes regression testing,
on x86_64-pc-linux-gnu, at least, adding a new rtl.sum with 46 PASSes
and 2 unsupported; stage 1 builds and passes selftesting and check-rtl
for target aarch64-linux-gnu.

I'm working on doing a full test across all our supported targets (and
there are likely some target-specific failures in there at the moment).

There are still some FIXMEs, TODOs and #if 0 in there, but I thought
it was worth posting to check that this is moving in the right
direction.

Thoughts?
Dave

David Malcolm (16):
  read-md.c: Add various cleanups to ~rtx_reader
  (approved) Add selftest::read_file
  (approved) selftest.h: add temp_override fixture
  (approved) Expose forcibly_ggc_collect and run it after all selftests
  Introduce rtl_data::init_stack_alignment
  Introduce emit_status::ensure_regno_capacity
  read-md: add some helper functions
  (partially-approved): Introduce selftest::locate_file
  Split class rtx_reader into base_rtx_reader vs rtx_reader
  Introduce class function_reader (v3)
  df selftests (v3)
  combine.c selftests (v2)
  cse.c selftests
  RTL interpreter (work-in-progress)
  RTL frontend (rtl1), on top of dump reader
  Add "__RTL" to cc1

 gcc/Makefile.in                                    |   14 +-
 gcc/c-family/c-common.c                            |    1 +
 gcc/c-family/c-common.h                            |    3 +
 gcc/c/c-parser.c                                   |  102 +-
 gcc/cfgexpand.c                                    |    5 +-
 gcc/combine.c                                      |  121 +
 gcc/common.opt                                     |    6 +-
 gcc/cse.c                                          |   70 +
 gcc/df-core.c                                      |   73 +
 gcc/doc/rtl-frontend.texi                          |  262 +++
 gcc/doc/rtl.texi                                   |    3 +
 gcc/emit-rtl.c                                     |   57 +-
 gcc/emit-rtl.h                                     |    2 +
 gcc/errors.c                                       |   23 +-
 gcc/errors.h                                       |   14 +
 gcc/function-tests.c                               |    2 +-
 gcc/function.c                                     |    3 +-
 gcc/function.h                                     |    2 +
 gcc/gcc.c                                          |    1 +
 gcc/genpreds.c                                     |    6 +-
 gcc/ggc-tests.c                                    |   28 +-
 gcc/print-rtl.c                                    |    4 +-
 gcc/read-md.c                                      |  220 +-
 gcc/read-md.h                                      |   89 +-
 gcc/read-rtl-function.c                            | 2448 ++++++++++++++++++++
 gcc/read-rtl-function.h                            |   40 +
 gcc/read-rtl.c                                     |  251 +-
 gcc/rtl-interpreter.c                              |  371 +++
 gcc/rtl-interpreter.h                              |   86 +
 gcc/rtl.c                                          |    2 +
 gcc/rtl.h                                          |    3 +
 gcc/rtl/Make-lang.in                               |   88 +
 gcc/rtl/config-lang.in                             |   36 +
 gcc/rtl/lang-specs.h                               |   25 +
 gcc/rtl/lang.opt                                   |   33 +
 gcc/rtl/rtl-errors.c                               |   34 +
 gcc/rtl/rtl-frontend.c                             |  399 ++++
 gcc/run-one-rtl-pass.c                             |  119 +
 gcc/run-one-rtl-pass.h                             |   25 +
 gcc/selftest-rtl.c                                 |   90 +
 gcc/selftest-rtl.h                                 |   67 +
 gcc/selftest-run-tests.c                           |   18 +
 gcc/selftest.c                                     |   88 +
 gcc/selftest.h                                     |   56 +
 gcc/testsuite/gcc.dg/cpp/pr71591.c                 |    2 +-
 gcc/testsuite/lib/rtl-dg.exp                       |   64 +
 gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl          |   32 +
 gcc/testsuite/rtl.dg/aarch64/pr71779.rtl           |   44 +
 gcc/testsuite/rtl.dg/cfg-extra-bb.rtl              |   12 +
 gcc/testsuite/rtl.dg/cfg-missing-bb.rtl            |   16 +
 gcc/testsuite/rtl.dg/good-include.rtl              |    6 +
 gcc/testsuite/rtl.dg/good-includee.md              |    5 +
 gcc/testsuite/rtl.dg/missing-include.rtl           |    1 +
 gcc/testsuite/rtl.dg/more-than-one-cfg.rtl         |    7 +
 gcc/testsuite/rtl.dg/rtl.exp                       |   43 +
 gcc/testsuite/rtl.dg/test.c                        |   31 +
 gcc/testsuite/rtl.dg/unknown-insn-uid.rtl          |    6 +
 gcc/testsuite/rtl.dg/unknown-rtx-code.rtl          |    5 +
 gcc/testsuite/rtl.dg/x86_64/dfinit.rtl             |  102 +
 gcc/testsuite/rtl.dg/x86_64/different-structs.c    |  101 +
 gcc/testsuite/rtl.dg/x86_64/final.rtl              |   58 +
 gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl     |   91 +
 gcc/testsuite/rtl.dg/x86_64/ira.rtl                |   91 +
 gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl   |   44 +
 .../x86_64/test-return-const.c.after-expand.c      |   23 +
 .../x86_64/test-return-const.c.before-fwprop.c     |   27 +
 gcc/testsuite/rtl.dg/x86_64/test-rtl.c             |   95 +
 .../rtl.dg/x86_64/times-two.c.after-expand.c       |   40 +
 .../rtl.dg/x86_64/times-two.c.before-df.c          |   57 +
 gcc/testsuite/rtl.dg/x86_64/vregs.rtl              |   88 +
 gcc/testsuite/selftests/aarch64/times-two.rtl      |   42 +
 gcc/testsuite/selftests/asr_div1.rtl               |   23 +
 gcc/testsuite/selftests/cfg-test.rtl               |   38 +
 gcc/testsuite/selftests/const-int.rtl              |   16 +
 .../selftests/copy-hard-reg-into-frame.rtl         |   12 +
 gcc/testsuite/selftests/example-labels.rtl         |    6 +
 gcc/testsuite/selftests/example.txt                |    1 +
 gcc/testsuite/selftests/insn-with-mode.rtl         |    5 +
 gcc/testsuite/selftests/jump-to-label-ref.rtl      |   11 +
 gcc/testsuite/selftests/jump-to-return.rtl         |   10 +
 gcc/testsuite/selftests/jump-to-simple-return.rtl  |   11 +
 gcc/testsuite/selftests/non-combinable-shifts.rtl  |   18 +
 gcc/testsuite/selftests/note-insn-deleted.rtl      |    5 +
 gcc/testsuite/selftests/note_insn_basic_block.rtl  |    5 +
 gcc/testsuite/selftests/pr71779.rtl                |   39 +
 .../selftests/rtl/interp/empty-function.rtl        |   19 +
 .../selftests/rtl/interp/simple-arith.rtl          |   13 +
 gcc/testsuite/selftests/rtl/interp/simple-set.rtl  |    7 +
 .../selftests/rtl/interp/undefined-read.rtl        |   11 +
 gcc/testsuite/selftests/simple-cse.rtl             |   12 +
 gcc/testsuite/selftests/single-set.rtl             |    5 +
 gcc/testsuite/selftests/symbol-ref.rtl             |    7 +
 gcc/testsuite/selftests/test-regno-renumbering.rtl |    6 +
 gcc/testsuite/selftests/x86_64/call-insn.rtl       |   12 +
 gcc/testsuite/selftests/x86_64/times-two.rtl       |   57 +
 gcc/toplev.c                                       |    7 +
 gcc/tree-dfa.c                                     |    5 +
 97 files changed, 6730 insertions(+), 154 deletions(-)
 create mode 100644 gcc/doc/rtl-frontend.texi
 create mode 100644 gcc/read-rtl-function.c
 create mode 100644 gcc/read-rtl-function.h
 create mode 100644 gcc/rtl-interpreter.c
 create mode 100644 gcc/rtl-interpreter.h
 create mode 100644 gcc/rtl/Make-lang.in
 create mode 100644 gcc/rtl/config-lang.in
 create mode 100644 gcc/rtl/lang-specs.h
 create mode 100644 gcc/rtl/lang.opt
 create mode 100644 gcc/rtl/rtl-errors.c
 create mode 100644 gcc/rtl/rtl-frontend.c
 create mode 100644 gcc/run-one-rtl-pass.c
 create mode 100644 gcc/run-one-rtl-pass.h
 create mode 100644 gcc/selftest-rtl.c
 create mode 100644 gcc/selftest-rtl.h
 create mode 100644 gcc/testsuite/lib/rtl-dg.exp
 create mode 100644 gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl
 create mode 100644 gcc/testsuite/rtl.dg/aarch64/pr71779.rtl
 create mode 100644 gcc/testsuite/rtl.dg/cfg-extra-bb.rtl
 create mode 100644 gcc/testsuite/rtl.dg/cfg-missing-bb.rtl
 create mode 100644 gcc/testsuite/rtl.dg/good-include.rtl
 create mode 100644 gcc/testsuite/rtl.dg/good-includee.md
 create mode 100644 gcc/testsuite/rtl.dg/missing-include.rtl
 create mode 100644 gcc/testsuite/rtl.dg/more-than-one-cfg.rtl
 create mode 100644 gcc/testsuite/rtl.dg/rtl.exp
 create mode 100644 gcc/testsuite/rtl.dg/test.c
 create mode 100644 gcc/testsuite/rtl.dg/unknown-insn-uid.rtl
 create mode 100644 gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/dfinit.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/different-structs.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/final.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/ira.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-rtl.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/vregs.rtl
 create mode 100644 gcc/testsuite/selftests/aarch64/times-two.rtl
 create mode 100644 gcc/testsuite/selftests/asr_div1.rtl
 create mode 100644 gcc/testsuite/selftests/cfg-test.rtl
 create mode 100644 gcc/testsuite/selftests/const-int.rtl
 create mode 100644 gcc/testsuite/selftests/copy-hard-reg-into-frame.rtl
 create mode 100644 gcc/testsuite/selftests/example-labels.rtl
 create mode 100644 gcc/testsuite/selftests/example.txt
 create mode 100644 gcc/testsuite/selftests/insn-with-mode.rtl
 create mode 100644 gcc/testsuite/selftests/jump-to-label-ref.rtl
 create mode 100644 gcc/testsuite/selftests/jump-to-return.rtl
 create mode 100644 gcc/testsuite/selftests/jump-to-simple-return.rtl
 create mode 100644 gcc/testsuite/selftests/non-combinable-shifts.rtl
 create mode 100644 gcc/testsuite/selftests/note-insn-deleted.rtl
 create mode 100644 gcc/testsuite/selftests/note_insn_basic_block.rtl
 create mode 100644 gcc/testsuite/selftests/pr71779.rtl
 create mode 100644 gcc/testsuite/selftests/rtl/interp/empty-function.rtl
 create mode 100644 gcc/testsuite/selftests/rtl/interp/simple-arith.rtl
 create mode 100644 gcc/testsuite/selftests/rtl/interp/simple-set.rtl
 create mode 100644 gcc/testsuite/selftests/rtl/interp/undefined-read.rtl
 create mode 100644 gcc/testsuite/selftests/simple-cse.rtl
 create mode 100644 gcc/testsuite/selftests/single-set.rtl
 create mode 100644 gcc/testsuite/selftests/symbol-ref.rtl
 create mode 100644 gcc/testsuite/selftests/test-regno-renumbering.rtl
 create mode 100644 gcc/testsuite/selftests/x86_64/call-insn.rtl
 create mode 100644 gcc/testsuite/selftests/x86_64/times-two.rtl

-- 
1.8.5.3

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

* [PATCH 15/16] RTL frontend (rtl1), on top of dump reader
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (8 preceding siblings ...)
  2016-10-05 15:45 ` [PATCH 05/16] Introduce rtl_data::init_stack_alignment David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-06 13:30   ` Bernd Schmidt
  2016-10-06 15:24   ` [PATCH 15/16] RTL frontend (rtl1), on top of dump reader Bernd Schmidt
  2016-10-05 15:45 ` [PATCH 14/16] RTL interpreter (work-in-progress) David Malcolm
                   ` (5 subsequent siblings)
  15 siblings, 2 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

This patch implements the RTL frontend, using the function_reader
class from earlier in the patch kit.

Compared to this patch in v1 of the kit, most of the work has been
split into earlier patches.  Other changes relative to v1 include:
* fix autodeps (by renaming RTL_OBJS to rtl_OBJS in rtl/Make-lang.in)
* cleanup of rtl/Make-lang.in
* overrride IN_GCC_FRONTEND in rtl/rtl-frontend.c
* split out run-one-rtl-pass.h/c
* added .texi docs to gccint (instead of notes.rst)
* remove roundtrip.exp for now (we don't currently preserve source
location information)
* convert existing test cases to "print_rtx_function" format, and add
new test cases.  Move some to target-specific subdirectories of rtl.dg
(manually adding target filters).

gcc/ChangeLog:
	* Makefile.in (OBJS): Add run-one-rtl-pass.o.
	* doc/rtl-frontend.texi: New file.
	* doc/rtl.texi (RTL Representation): Add "RTL Frontend" to menu.
	Include rtl-frontend.texi.
	* gcc.c (default_compilers): Add a ".rtl" entry.
	* read-rtl-function.c (read_rtl_function_body): Set
	in_rtl_frontend_p.
	* rtl.c (in_rtl_frontend_p): New global.
	* rtl.h (in_rtl_frontend_p): New global decl.
	* run-one-rtl-pass.c: New file.
	* run-one-rtl-pass.h: New file.
	* toplev.c (compile_file): Bail out after the parse_file
	langhook if within the RTL frontend.

gcc/rtl/ChangeLog:
	* ChangeLog: New file.
	* Make-lang.in: New file.
	* config-lang.in: New file.
	* lang-specs.h: New file.
	* lang.opt: New file.
	* rtl-errors.c: New file.
	* rtl-frontend.c: New file.

gcc/testsuite/ChangeLog:
	* lib/rtl-dg.exp: New file.
	* rtl.dg/aarch64/asr_div1.rtl: New file.
	* rtl.dg/aarch64/pr71779.rtl: New file.
	* rtl.dg/cfg-extra-bb.rtl: New file.
	* rtl.dg/cfg-missing-bb.rtl: New file.
	* rtl.dg/good-include.rtl: New file.
	* rtl.dg/good-includee.md: New file.
	* rtl.dg/missing-include.rtl: New file.
	* rtl.dg/more-than-one-cfg.rtl: New file.
	* rtl.dg/rtl.exp: New file.
	* rtl.dg/test.c: New file.
	* rtl.dg/unknown-insn-uid.rtl: New file.
	* rtl.dg/unknown-rtx-code.rtl: New file.
	* rtl.dg/x86_64/dfinit.rtl: New file.
	* rtl.dg/x86_64/final.rtl: New file.
	* rtl.dg/x86_64/into-cfglayout.rtl: New file.
	* rtl.dg/x86_64/ira.rtl: New file.
	* rtl.dg/x86_64/pro_and_epilogue.rtl: New file.
	* rtl.dg/x86_64/vregs.rtl: New file.
---
 gcc/Makefile.in                                  |   1 +
 gcc/doc/rtl-frontend.texi                        | 262 +++++++++++++++
 gcc/doc/rtl.texi                                 |   3 +
 gcc/gcc.c                                        |   1 +
 gcc/read-rtl-function.c                          |   2 +
 gcc/rtl.c                                        |   2 +
 gcc/rtl.h                                        |   1 +
 gcc/rtl/Make-lang.in                             |  88 +++++
 gcc/rtl/config-lang.in                           |  36 ++
 gcc/rtl/lang-specs.h                             |  25 ++
 gcc/rtl/lang.opt                                 |  33 ++
 gcc/rtl/rtl-errors.c                             |  34 ++
 gcc/rtl/rtl-frontend.c                           | 399 +++++++++++++++++++++++
 gcc/run-one-rtl-pass.c                           | 119 +++++++
 gcc/run-one-rtl-pass.h                           |  25 ++
 gcc/testsuite/lib/rtl-dg.exp                     |  64 ++++
 gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl        |  32 ++
 gcc/testsuite/rtl.dg/aarch64/pr71779.rtl         |  44 +++
 gcc/testsuite/rtl.dg/cfg-extra-bb.rtl            |  12 +
 gcc/testsuite/rtl.dg/cfg-missing-bb.rtl          |  16 +
 gcc/testsuite/rtl.dg/good-include.rtl            |   6 +
 gcc/testsuite/rtl.dg/good-includee.md            |   5 +
 gcc/testsuite/rtl.dg/missing-include.rtl         |   1 +
 gcc/testsuite/rtl.dg/more-than-one-cfg.rtl       |   7 +
 gcc/testsuite/rtl.dg/rtl.exp                     |  41 +++
 gcc/testsuite/rtl.dg/test.c                      |  31 ++
 gcc/testsuite/rtl.dg/unknown-insn-uid.rtl        |   6 +
 gcc/testsuite/rtl.dg/unknown-rtx-code.rtl        |   5 +
 gcc/testsuite/rtl.dg/x86_64/dfinit.rtl           | 102 ++++++
 gcc/testsuite/rtl.dg/x86_64/final.rtl            |  58 ++++
 gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl   |  91 ++++++
 gcc/testsuite/rtl.dg/x86_64/ira.rtl              |  91 ++++++
 gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl |  44 +++
 gcc/testsuite/rtl.dg/x86_64/vregs.rtl            |  88 +++++
 gcc/toplev.c                                     |   7 +
 35 files changed, 1782 insertions(+)
 create mode 100644 gcc/doc/rtl-frontend.texi
 create mode 100644 gcc/rtl/Make-lang.in
 create mode 100644 gcc/rtl/config-lang.in
 create mode 100644 gcc/rtl/lang-specs.h
 create mode 100644 gcc/rtl/lang.opt
 create mode 100644 gcc/rtl/rtl-errors.c
 create mode 100644 gcc/rtl/rtl-frontend.c
 create mode 100644 gcc/run-one-rtl-pass.c
 create mode 100644 gcc/run-one-rtl-pass.h
 create mode 100644 gcc/testsuite/lib/rtl-dg.exp
 create mode 100644 gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl
 create mode 100644 gcc/testsuite/rtl.dg/aarch64/pr71779.rtl
 create mode 100644 gcc/testsuite/rtl.dg/cfg-extra-bb.rtl
 create mode 100644 gcc/testsuite/rtl.dg/cfg-missing-bb.rtl
 create mode 100644 gcc/testsuite/rtl.dg/good-include.rtl
 create mode 100644 gcc/testsuite/rtl.dg/good-includee.md
 create mode 100644 gcc/testsuite/rtl.dg/missing-include.rtl
 create mode 100644 gcc/testsuite/rtl.dg/more-than-one-cfg.rtl
 create mode 100644 gcc/testsuite/rtl.dg/rtl.exp
 create mode 100644 gcc/testsuite/rtl.dg/test.c
 create mode 100644 gcc/testsuite/rtl.dg/unknown-insn-uid.rtl
 create mode 100644 gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/dfinit.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/final.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/ira.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/vregs.rtl

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 3582bde..1c7c548 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1432,6 +1432,7 @@ OBJS = \
 	rtlhash.o \
 	rtlanal.o \
 	rtlhooks.o \
+	run-one-rtl-pass.o \
 	sbitmap.o \
 	sched-deps.o \
 	sched-ebb.o \
diff --git a/gcc/doc/rtl-frontend.texi b/gcc/doc/rtl-frontend.texi
new file mode 100644
index 0000000..b87794a
--- /dev/null
+++ b/gcc/doc/rtl-frontend.texi
@@ -0,0 +1,262 @@
+@node RTL Frontend
+@section RTL Frontend
+
+@subsection Purpose
+
+Historically GCC testing has been done by providing source files
+to be built with various command-line options (via DejaGnu
+directives), dumping state at pertinent places, and verifying
+properties of the state via these dumps.
+
+A strength of this approach is that we have excellent integration
+testing, as every test case exercises the toolchain as a whole, but
+it has the drawback that when testing a specific pass,
+we have little control of the input to that specific pass.  We
+provide input, and the various passes transform the state
+of the internal representation:
+
+@smallexample
+  INPUT -> PASS-1 -> STATE-1 -> PASS-2 -> STATE-2 -> ...
+    -> etc ->
+    -> ... -> PASS-n-1 -> STATE-n-1 -> PASS-n -> STATE-n
+                          ^            ^         ^
+                          |            |         Output from the pass
+                          |            The pass we care about
+                          The actual input to the pass
+@end smallexample
+
+so the intervening passes before "PASS-n" could make changes to the
+IR that affect the input seen by our pass ("STATE-n-1" above).  This
+can break our test cases, sometimes in a form that's visible,
+sometimes invisibly (e.g. where a test case silently stops providing
+coverage).
+
+The aim of the RTL frontend is to provide a convenient way to test
+individual passes in the backend, by loading dumps of specific RTL
+state (possibly edited by hand), and then running just one specific
+pass on them, so that we effectively have this:
+
+@smallexample
+  INPUT -> PASS-n -> OUTPUT
+@end smallexample
+
+thus fixing the problem above.
+
+The goal is to make it easy to write more fine-grained and
+robust test coverage for the RTL phase of GCC.  However this should be
+seen as @emph{complementary} to the existing "integrated testing" approach:
+patches should include both RTL frontend tests @emph{and} integrated tests,
+to avoid regressing the great integration testing we currently have.
+
+The idea is to use the existing dump format as a input format, since
+presumably existing GCC developers are very familiar with the dump
+format.
+
+One other potential benefit of this approach is to allow unit-testing
+of machine descriptions - we could provide specific RTL fragments,
+and have the @file{rtl.dg} testsuite directly verify that we recognize all
+instructions and addressing modes that a given target ought to support.
+
+@subsection Structure
+
+The RTL frontend is similar to a regular frontend: a @file{gcc/rtl}
+subdirectory within the source tree contains frontend-specific hooks.
+These provide a new @code{rtl} frontend, which can be optionally
+enabled at configuration time within @option{--enable-languages}.
+
+If enabled, it builds an @command{rtl1} binary, which is invoked by the
+@command{gcc} driver on files with a @file{.rtl} extension.
+
+The testsuite is below @file{gcc/testsuite/rtl.dg}.
+
+@subsection Input format
+
+Input files should have a @file{.rtl} extension.
+
+The parser accepts the format emitted by @code{print_rtx_function}:
+
+@smallexample
+(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"
+@end smallexample
+
+To make it easier to hand-edit file, the @code{(cfg)} and @code{(crtl)}
+directives can be omitted.  If the @code{(cfg)} directive is omitted,
+then the parser frontend reconstructs the edges implied by jump
+instructions.  This ought to work OK for ``cfgrtl'' mode, but isn't
+going to work for ``cfglayout'' mode - in the latter, unconditional jumps
+are represented purely by edges in the CFG, and so this information must
+be provided by a @code{(cfg)} directive.  See
+@uref{https://gcc.gnu.org/wiki/cfglayout_mode} for more information
+on ``cfgrtl'' mode vs ``cfglayout mode''.
+
+@subsection Register numbers
+
+print_rtx will print a name for hard and virtual registers
+after the register number, and no name for pseudos.
+
+The parser looks for a name after the number.  If there is, such as:
+
+@smallexample
+  (reg/f:DI 82 virtual-stack-vars)
+@end smallexample
+
+it assumes a hard or virtual reg, and tries to parse the name:
+
+@itemize @bullet
+
+@item
+if the name is recognized, it uses the target's current number for that
+name (future-proofing virtuals against @file{.md} changes)
+
+@item
+if the name is not recognized, issue a fatal error (it's probably a
+typo, or maybe a backport from a future version of gcc, or a target
+incompatibility)
+
+@item
+if there's no name, it assumes it's a pseudo.  If any such the registers
+appear in the dump with a register number <= @code{LAST_VIRTUAL_REGISTER},
+then all such pseudos have their register number adjusted by an offset so
+that all are > @code{LAST_VIRTUAL_REGISTER}, to future-proof against
+@file{.md} changes, and to allow some measure of target-independence.
+Otherwise, the numbering is left untouched (the common case).
+
+@end itemize
+
+
+@subsection Limitations
+
+@itemize @bullet
+
+@item
+It's a work-in-progress.  There will be bugs.
+
+
+@item
+The existing RTL code is structured around a single function being
+optimized, so, as a simplification, the RTL frontend can only handle
+one function per input file.
+
+@item
+The RTL frontend doesn't have any knowledge of parameters, types,
+locals, globals, etc.  It creates a single function.
+The function is currently hardcoded to have this signature:
+
+     int NAME (int, int, int);
+
+since there's no syntax for specify otherwise, and we need to provide
+a @code{FUNCTION_DECL} tree when building a function object (by calling
+@code{allocate_struct_function}).
+
+@item
+Similarly, there are no types beyond the built-in ones; all expressions
+are treated as being of type @code{int}.  I suspect that this approach
+will be too simplistic when it comes to e.g. aliasing.
+
+@item
+There's no support for running more than one pass; fixing this would
+require being able to run passes from a certain point onwards.
+
+@item
+Roundtripping of recognized instructions may be an issue (i.e. those
+with @code{INSN_CODE} != -1), such as the ``667 @{jump@}'' in the
+following:
+
+@smallexample
+    (jump_insn 50 49 51 10
+      (set (pc)
+           (label_ref:DI 59)) ../../src/test-switch.c:18 667 @{jump@}
+           (nil) -> 59)
+@end smallexample
+
+since the integer ID can change when the @file{.md} files are changed
+(and the associated pattern name is very much target-specific).
+Currently the loaded ignores them, resetting the @code{INSN_CODE} to -1.
+An alternative strategy would be to lookup the insn by name, and
+use the correct @code{INSN_CODE} (future-proofing against @file{.md}
+changes, but making dumps more target-specific).
+
+@end itemize
+
+@subsection TODO items
+
+@itemize @bullet
+
+@item
+test with other architectures
+
+@item
+example with "-g"
+
+@item
+implement a fuzzer (or use AFL on the existing test cases)
+
+@end itemize
+
+@subsection Cross-arch issues
+
+Test cases are likely to be target-specific.  Examples include:
+
+@itemize @bullet
+
+@item
+unknown modes e.g. this from x86_64:
+
+@smallexample
+    (reg:CCGC 17 flags)
+@end smallexample
+
+fails on aarch64 due to the lack of a "CCGC" mode.
+
+@end itemize
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 692d9b5..9e86df9 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -41,6 +41,7 @@ form uses nested parentheses to indicate the pointers in the internal form.
 * Calls::             RTL representation of function call insns.
 * Sharing::           Some expressions are unique; others *must* be copied.
 * Reading RTL::       Reading textual RTL from a file.
+* RTL Frontend::      Testing GCC using RTL dumps.
 @end menu
 
 @node RTL Objects
@@ -4236,3 +4237,5 @@ The proper way to interface GCC to a new language front end is with
 the ``tree'' data structure, described in the files @file{tree.h} and
 @file{tree.def}.  The documentation for this structure (@pxref{GENERIC})
 is incomplete.
+
+@include rtl-frontend.texi
diff --git a/gcc/gcc.c b/gcc/gcc.c
index fd2b182..7a21a74 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1296,6 +1296,7 @@ static const struct compiler default_compilers[] =
   {".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0},
   {".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0},
   {".go", "#Go", 0, 1, 0},
+  {".rtl", "#RTL", 0, 1, 0},
   /* Next come the entries for C.  */
   {".c", "@c", 0, 0, 1},
   {"@c",
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
index 0cd34d4..0723585 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -1801,6 +1801,8 @@ read_rtl_function_body (int argc, const char **argv,
 			function_reader_policy *policy,
 			int *out_pseudo_offset)
 {
+  in_rtl_frontend_p = true;
+
   initialize_rtl ();
   init_emit ();
   init_varasm_status ();
diff --git a/gcc/rtl.c b/gcc/rtl.c
index a445cdc..9729c82 100644
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -878,3 +878,5 @@ rtl_check_failed_flag (const char *name, const_rtx r, const char *file,
      name, GET_RTX_NAME (GET_CODE (r)), func, trim_filename (file), line);
 }
 #endif /* ENABLE_RTL_FLAG_CHECKING */
+
+bool in_rtl_frontend_p = false;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 0741fc6..813d7a9 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3748,5 +3748,6 @@ struct GTY(()) cgraph_rtl_info {
   unsigned function_used_regs_valid: 1;
 };
 
+extern bool in_rtl_frontend_p;
 
 #endif /* ! GCC_RTL_H */
diff --git a/gcc/rtl/Make-lang.in b/gcc/rtl/Make-lang.in
new file mode 100644
index 0000000..74d0a3e
--- /dev/null
+++ b/gcc/rtl/Make-lang.in
@@ -0,0 +1,88 @@
+# Make-lang.in -- Top level -*- makefile -*- fragment for RTL frontend.
+
+# 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/>.
+
+# This file provides the language dependent support in the main Makefile.
+
+# The name for selecting the RTL frontend in LANGUAGES.
+rtl: rtl1$(exeext)
+
+.PHONY: rtl
+
+# Use strict warnings.
+rtl-warn = $(STRICT_WARN)
+
+rtl_OBJS = \
+	rtl/rtl-errors.o \
+	rtl/rtl-frontend.o
+
+rtl1$(exeext): $(rtl_OBJS) attribs.o $(BACKEND) $(LIBDEPS)
+	+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+	      $(rtl_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS)
+
+# Build hooks:
+
+rtl.all.cross:
+rtl.start.encap:
+rtl.rest.encap:
+rtl.info:
+rtl.dvi:
+rtl.html:
+rtl.pdf:
+rtl.man:
+
+lang_checks += check-rtl
+lang_checks_parallelized += check-rtl
+check_rtl_parallelize = 10
+
+# Install hooks.
+
+rtl.install-common:
+rtl.install-man:
+rtl.install-plugin:
+rtl.install-info:
+rtl.install-pdf:
+rtl.install-html:
+rtl.uninstall:
+
+# Clean hooks.
+
+rtl.mostlyclean:
+	-rm -f rtl1$(exeext)
+	-rm -f rtl/*$(objext)
+	-rm -f rtl/*$(coverageexts)
+rtl.clean:
+rtl.distclean:
+	-rm -f rtl/config.status rtl/Makefile
+rtl.maintainer-clean:
+
+# Stage hooks.
+
+rtl.stage1: stage1-start
+	-mv rtl/*$(objext) stage1/rtl
+rtl.stage2: stage2-start
+	-mv rtl/*$(objext) stage2/rtl
+rtl.stage3: stage3-start
+	-mv rtl/*$(objext) stage3/rtl
+rtl.stage4: stage4-start
+	-mv rtl/*$(objext) stage4/rtl
+rtl.stageprofile: stageprofile-start
+	-mv rtl/*$(objext) stageprofile/rtl
+rtl.stagefeedback: stagefeedback-start
+	-mv rtl/*$(objext) stagefeedback/rtl
diff --git a/gcc/rtl/config-lang.in b/gcc/rtl/config-lang.in
new file mode 100644
index 0000000..3b101ce
--- /dev/null
+++ b/gcc/rtl/config-lang.in
@@ -0,0 +1,36 @@
+# config-lang.in -- Top level configure fragment for RTL frontend.
+
+# 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/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language	- name of language as it would appear in $(LANGUAGES)
+# compilers	- value to add to $(COMPILERS)
+
+language="rtl"
+
+compilers="rtl1\$(exeext)"
+
+target_libs=""
+
+gtfiles="\$(srcdir)/rtl/rtl-frontend.c"
+
+# Do not build by default.
+build_by_default="no"
diff --git a/gcc/rtl/lang-specs.h b/gcc/rtl/lang-specs.h
new file mode 100644
index 0000000..2af33ab
--- /dev/null
+++ b/gcc/rtl/lang-specs.h
@@ -0,0 +1,25 @@
+/* lang-specs.h -- gcc driver specs for RTL frontend.
+   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/>.  */
+
+/* This is the contribution to the `default_compilers' array in gcc.c
+   for the RTL frontend.  */
+
+{".rtl",  "@RTL", 0, 1, 0},
+{"@RTL",  "rtl1 %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}",
+    0, 1, 0},
diff --git a/gcc/rtl/lang.opt b/gcc/rtl/lang.opt
new file mode 100644
index 0000000..2515ff3
--- /dev/null
+++ b/gcc/rtl/lang.opt
@@ -0,0 +1,33 @@
+; lang.opt -- Options for the gcc RTL front end.
+
+; 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/>.
+
+; See the GCC internals manual for a description of this file's format.
+
+; Please try to keep this file in ASCII collating order.
+
+Language
+RTL
+
+fsingle-pass=
+RTL Joined RejectNegative
+After loading the RTL input file, run the specified pass on it.
+
+
+; This comment is to ensure we retain the blank line above.
diff --git a/gcc/rtl/rtl-errors.c b/gcc/rtl/rtl-errors.c
new file mode 100644
index 0000000..1859cb6
--- /dev/null
+++ b/gcc/rtl/rtl-errors.c
@@ -0,0 +1,34 @@
+/* rtl-error.c - Replacement for errors.c for use by RTL frontend
+   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 "errors.h"
+
+/* Stub implementation of RTL error-handling for use by RTL frontend.  */
+
+void
+fatal (const char *, ...)
+{
+  abort ();
+}
+
+int have_error;
+
diff --git a/gcc/rtl/rtl-frontend.c b/gcc/rtl/rtl-frontend.c
new file mode 100644
index 0000000..638b104
--- /dev/null
+++ b/gcc/rtl/rtl-frontend.c
@@ -0,0 +1,399 @@
+/* rtl-frontend.c - Top-level of RTL frontend
+   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/>.  */
+
+/* Front ends normally should never have to include RTL headers.
+   This is enforced in system.h by poisoning various header double-include
+   protection defines.
+   However, for obvious reasons, the RTL frontend needs RTL headers.
+   Override this protection for this special case.  */
+#undef IN_GCC_FRONTEND
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "stor-layout.h"
+#include "debug.h"
+#include "convert.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "common/common-target.h"
+#include "read-md.h"
+#include <mpfr.h>
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "pass_manager.h"
+#include "toplev.h"
+#include "bitmap.h"
+#include "df.h"
+#include "regs.h"
+#include "varasm.h"
+#include "insn-addr.h"
+#include "read-rtl-function.h"
+#include "run-one-rtl-pass.h"
+
+/* Language-dependent contents of a type.  */
+
+struct GTY(()) lang_type
+{
+  char dummy;
+};
+
+/* Language-dependent contents of a decl.  */
+
+struct GTY(()) lang_decl
+{
+  char dummy;
+};
+
+/* Language-dependent contents of an identifier.  This must include a
+   tree_identifier.  */
+
+struct GTY(()) lang_identifier
+{
+  struct tree_identifier common;
+};
+
+/* The resulting tree type.  */
+
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+	   chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+  union tree_node GTY((tag ("0"),
+		       desc ("tree_node_structure (&%h)"))) generic;
+  struct lang_identifier GTY((tag ("1"))) identifier;
+};
+
+/* We don't use language_function.  */
+
+struct GTY(()) language_function
+{
+  int dummy;
+};
+
+/* Language hooks.  */
+
+/* Implementation of LANG_HOOKS_INIT for the RTL frontend.  */
+
+static bool
+rtl_langhook_init (void)
+{
+  in_rtl_frontend_p = true;
+
+  build_common_tree_nodes (false);
+
+  /* I don't know why this has to be done explicitly.  */
+  void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+  build_common_builtin_nodes ();
+
+  /* The default precision for floating point numbers.  This is used
+     for floating point constants with abstract type.  This may
+     eventually be controllable by a command line option.  */
+  mpfr_set_default_prec (256);
+
+  return true;
+}
+
+/* Implementation of LANG_HOOKS_OPTION_LANG_MASK for the RTL frontend.  */
+
+static unsigned int
+rtl_langhook_option_lang_mask (void)
+{
+  return CL_RTL;
+}
+
+/* The value of "-fsingle-pass=", if any.  */
+
+static const char *single_pass_name = NULL;
+
+/* Implementation of LANG_HOOKS_HANDLE_OPTION for the RTL frontend.  */
+
+static bool
+rtl_langhook_handle_option (
+    size_t scode,
+    const char *arg,
+    int value ATTRIBUTE_UNUSED,
+    int kind ATTRIBUTE_UNUSED,
+    location_t loc ATTRIBUTE_UNUSED,
+    const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+{
+  enum opt_code code = (enum opt_code) scode;
+
+  switch (code)
+    {
+    case OPT_fsingle_pass_:
+      single_pass_name =  xstrdup (arg);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+/* Implementation of LANG_HOOKS_PARSE_FILE for the RTL frontend.  */
+
+static void
+rtl_langhook_parse_file (void)
+{
+  in_rtl_frontend_p = true;
+
+  initialize_rtl ();
+  init_emit ();
+  init_varasm_status ();
+
+  auto_vec<const char *> argv (num_in_fnames + 1);
+  argv.safe_push (progname);
+  for (unsigned i = 0; i < num_in_fnames; i++)
+    argv.safe_push (in_fnames[i]);
+  if (!read_rtl_function_body (argv.length (), argv.address (), NULL, NULL,
+			       NULL))
+    return;
+
+  /*  If -fsingle-pass=PASS_NAME was provided, locate and run PASS_NAME
+      on cfun, as created above.  */
+  if (single_pass_name)
+    run_one_rtl_pass_by_name (single_pass_name);
+}
+
+/* Implementation of LANG_HOOKS_TYPE_FOR_SIZE, taken from Go frontend.  */
+
+static tree
+rtl_langhook_type_for_size (unsigned int bits, int unsignedp)
+{
+  tree type;
+  if (unsignedp)
+    {
+      if (bits == INT_TYPE_SIZE)
+        type = unsigned_type_node;
+      else if (bits == CHAR_TYPE_SIZE)
+        type = unsigned_char_type_node;
+      else if (bits == SHORT_TYPE_SIZE)
+        type = short_unsigned_type_node;
+      else if (bits == LONG_TYPE_SIZE)
+        type = long_unsigned_type_node;
+      else if (bits == LONG_LONG_TYPE_SIZE)
+        type = long_long_unsigned_type_node;
+      else
+        type = make_unsigned_type(bits);
+    }
+  else
+    {
+      if (bits == INT_TYPE_SIZE)
+        type = integer_type_node;
+      else if (bits == CHAR_TYPE_SIZE)
+        type = signed_char_type_node;
+      else if (bits == SHORT_TYPE_SIZE)
+        type = short_integer_type_node;
+      else if (bits == LONG_TYPE_SIZE)
+        type = long_integer_type_node;
+      else if (bits == LONG_LONG_TYPE_SIZE)
+        type = long_long_integer_type_node;
+      else
+        type = make_signed_type(bits);
+    }
+  return type;
+}
+
+/* Implementation of LANG_HOOKS_TYPE_FOR_MODE, taken from Go frontend.  */
+
+static tree
+rtl_langhook_type_for_mode (machine_mode mode, int unsignedp)
+{
+  tree type;
+  /* Go has no vector types.  Build them here.  FIXME: It does not
+     make sense for the middle-end to ask the frontend for a type
+     which the frontend does not support.  However, at least for now
+     it is required.  See PR 46805.  */
+  if (VECTOR_MODE_P (mode))
+    {
+      tree inner;
+
+      inner = rtl_langhook_type_for_mode (GET_MODE_INNER (mode), unsignedp);
+      if (inner != NULL_TREE)
+	return build_vector_type_for_mode (inner, mode);
+      return NULL_TREE;
+    }
+
+  // FIXME: This static_cast should be in machmode.h.
+  enum mode_class mc = static_cast<enum mode_class>(GET_MODE_CLASS(mode));
+  if (mc == MODE_INT)
+    return rtl_langhook_type_for_size(GET_MODE_BITSIZE(mode), unsignedp);
+  else if (mc == MODE_FLOAT)
+    {
+      switch (GET_MODE_BITSIZE (mode))
+	{
+	case 32:
+	  return float_type_node;
+	case 64:
+	  return double_type_node;
+	default:
+	  // We have to check for long double in order to support
+	  // i386 excess precision.
+	  if (mode == TYPE_MODE(long_double_type_node))
+	    return long_double_type_node;
+	}
+    }
+  else if (mc == MODE_COMPLEX_FLOAT)
+    {
+      switch (GET_MODE_BITSIZE (mode))
+	{
+	case 64:
+	  return complex_float_type_node;
+	case 128:
+	  return complex_double_type_node;
+	default:
+	  // We have to check for long double in order to support
+	  // i386 excess precision.
+	  if (mode == TYPE_MODE(complex_long_double_type_node))
+	    return complex_long_double_type_node;
+	}
+    }
+
+#if HOST_BITS_PER_WIDE_INT >= 64
+  /* The middle-end and some backends rely on TImode being supported
+     for 64-bit HWI.  */
+  if (mode == TImode)
+    {
+      type = build_nonstandard_integer_type (GET_MODE_BITSIZE (TImode),
+					     unsignedp);
+      if (type && TYPE_MODE (type) == TImode)
+	return type;
+    }
+#endif
+  return NULL_TREE;
+}
+
+/* Implementation of LANG_HOOKS_BUILTIN_FUNCTION.  */
+
+static tree
+rtl_langhook_builtin_function (tree decl)
+{
+  return decl;
+}
+
+/* Implementation of LANG_HOOKS_GLOBAL_BINDINGS_P.
+   Return true if we are in the global binding level.  */
+
+static bool
+rtl_langhook_global_bindings_p (void)
+{
+  return current_function_decl == NULL_TREE;
+}
+
+/* Implementation of LANG_HOOKS_PUSHDECL.  */
+
+static tree
+rtl_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+/* Implementation of LANG_HOOKS_GETDECLS.  */
+
+static tree
+rtl_langhook_getdecls (void)
+{
+  return NULL;
+}
+
+/* Functions called directly by the generic backend.  */
+
+/* Implementation of "convert" taken from the Go frontend.  */
+
+tree
+convert (tree type, tree expr)
+{
+  if (type == error_mark_node
+      || expr == error_mark_node
+      || TREE_TYPE (expr) == error_mark_node)
+    return error_mark_node;
+
+  if (type == TREE_TYPE (expr))
+    return expr;
+
+  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
+    return fold_convert (type, expr);
+
+  switch (TREE_CODE (type))
+    {
+    case VOID_TYPE:
+    case BOOLEAN_TYPE:
+      return fold_convert (type, expr);
+    case INTEGER_TYPE:
+      return fold (convert_to_integer (type, expr));
+    case POINTER_TYPE:
+      return fold (convert_to_pointer (type, expr));
+    case REAL_TYPE:
+      return fold (convert_to_real (type, expr));
+    case COMPLEX_TYPE:
+      return fold (convert_to_complex (type, expr));
+    default:
+      break;
+    }
+
+  gcc_unreachable ();
+}
+
+#undef LANG_HOOKS_NAME
+#undef LANG_HOOKS_INIT
+#undef LANG_HOOKS_OPTION_LANG_MASK
+#undef LANG_HOOKS_HANDLE_OPTION
+#undef LANG_HOOKS_PARSE_FILE
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#undef LANG_HOOKS_PUSHDECL
+#undef LANG_HOOKS_GETDECLS
+
+#define LANG_HOOKS_NAME			"GCC RTL frontend"
+#define LANG_HOOKS_INIT			rtl_langhook_init
+#define LANG_HOOKS_OPTION_LANG_MASK	rtl_langhook_option_lang_mask
+#define LANG_HOOKS_HANDLE_OPTION	rtl_langhook_handle_option
+#define LANG_HOOKS_PARSE_FILE		rtl_langhook_parse_file
+#define LANG_HOOKS_TYPE_FOR_MODE	rtl_langhook_type_for_mode
+#define LANG_HOOKS_TYPE_FOR_SIZE	rtl_langhook_type_for_size
+#define LANG_HOOKS_BUILTIN_FUNCTION	rtl_langhook_builtin_function
+#define LANG_HOOKS_GLOBAL_BINDINGS_P	rtl_langhook_global_bindings_p
+#define LANG_HOOKS_PUSHDECL		rtl_langhook_pushdecl
+#define LANG_HOOKS_GETDECLS		rtl_langhook_getdecls
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-rtl-rtl-frontend.h"
+#include "gtype-rtl.h"
diff --git a/gcc/run-one-rtl-pass.c b/gcc/run-one-rtl-pass.c
new file mode 100644
index 0000000..ced81a2
--- /dev/null
+++ b/gcc/run-one-rtl-pass.c
@@ -0,0 +1,119 @@
+/* run-one-rtl-pass.c - Run just one RTL pass
+   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 "target.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "stor-layout.h"
+#include "debug.h"
+#include "convert.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "common/common-target.h"
+#include "read-md.h"
+#include <mpfr.h>
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "pass_manager.h"
+#include "toplev.h"
+#include "bitmap.h"
+#include "df.h"
+#include "regs.h"
+#include "varasm.h"
+#include "insn-addr.h"
+
+/*  Locate and run PASS_NAME on cfun.  */
+
+void
+run_one_rtl_pass_by_name (const char *pass_name)
+{
+  opt_pass *pass = g->get_passes ()->get_pass_by_name (pass_name);
+  if (!pass)
+    {
+      error_at (UNKNOWN_LOCATION, "unrecognized pass: %qs", pass_name);
+      return;
+    }
+
+  /* Forcibly create the dataflow instance.  We'll need to do this on passes
+     that normally occur after pass_df_initialize/pass_df_initialize_no_opt.  */
+  /* FIXME: better conditional logic here.  */
+  if (0 == strcmp (pass_name, "rtl-cse1")
+      || 0 == strcmp (pass_name, "rtl-fwprop1")
+      || 0 == strcmp (pass_name, "rtl-combine")
+      || 0 == strcmp (pass_name, "rtl-ira")
+      || 0 == strcmp (pass_name, "rtl-reload")
+      || 0 == strcmp (pass_name, "rtl-pro_and_epilogue"))
+    {
+      opt_pass *df_pass = g->get_passes ()->get_pass_by_name ("rtl-dfinit");
+      gcc_assert (df_pass);
+      current_function_decl = cfun->decl;
+      df_pass->execute (cfun);
+
+      /* The dataflow instance should now exist.  */
+      gcc_assert (df);
+
+      df_analyze ();
+    }
+
+  /* Ensure reg_renumber is set up.  */
+  resize_reg_info ();
+
+  max_regno = max_reg_num ();
+
+  /* Pass "reload" sets the global "reload_completed", and many things
+     depend on this (e.g. instructions in .md files).  */
+  /* FIXME: better conditional logic here.  */
+  if (0 == strcmp (pass_name, "rtl-final"))
+    reload_completed = 1;
+
+  /* The INSN_ADDRESSES vec is normally set up by shorten_branches; we must
+     manually set it up for passes that run after this.  */
+  /* FIXME: better conditional logic here.  */
+  if (0 == strcmp (pass_name, "rtl-final"))
+    INSN_ADDRESSES_ALLOC (get_max_uid ());
+
+  /* Run the user-specified pass.  */
+  bitmap_obstack_initialize (NULL);
+  bitmap_obstack_initialize (&reg_obstack);
+  pass_init_dump_file (pass);
+  current_function_decl = cfun->decl;
+  pass->execute (cfun);
+  current_function_decl = NULL;
+  if (dump_file)
+    print_rtl_with_bb (dump_file, get_insns (), dump_flags);
+  pass_fini_dump_file (pass);
+  bitmap_obstack_release (&reg_obstack);
+}
diff --git a/gcc/run-one-rtl-pass.h b/gcc/run-one-rtl-pass.h
new file mode 100644
index 0000000..40d60ba
--- /dev/null
+++ b/gcc/run-one-rtl-pass.h
@@ -0,0 +1,25 @@
+/* run-one-rtl-pass.h - Run just one RTL pass
+   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/>.  */
+
+#ifndef GCC_RUN_ONE_RTL_PASS_H
+#define GCC_RUN_ONE_RTL_PASS_H
+
+extern void run_one_rtl_pass_by_name (const char *pass_name);
+
+#endif /* GCC_RUN_ONE_RTL_PASS_H */
diff --git a/gcc/testsuite/lib/rtl-dg.exp b/gcc/testsuite/lib/rtl-dg.exp
new file mode 100644
index 0000000..8aa5943
--- /dev/null
+++ b/gcc/testsuite/lib/rtl-dg.exp
@@ -0,0 +1,64 @@
+#   Copyright (C) 1997, 1999, 2000, 2003, 2007 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+# 
+# This program 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/>.
+
+# Define rtl callbacks for dg.exp.
+
+# Load support procs.
+load_lib gcc-defs.exp
+
+proc rtl_target_compile { source dest type options } {
+    set result [target_compile $source $dest $type $options]
+    return $result
+}
+
+load_lib gcc-dg.exp
+
+proc rtl-dg-test { prog do_what extra_tool_flags } {
+    verbose "rtl-dg-test (rtl-dg.exp):" 3
+    verbose "  prog: $prog" 3
+    verbose "  do_what: $do_what" 3
+    verbose "  extra_tool_flags: $extra_tool_flags" 3
+
+    return [gcc-dg-test-1 rtl_target_compile $prog $do_what $extra_tool_flags]
+}
+
+
+proc rtl-dg-prune { system text } {
+    return [gcc-dg-prune $system $text]
+}
+
+# Modified dg-runtest that runs tests in both C++98 and C++11 modes
+# unless they specifically specify one or the other.
+proc rtl-dg-runtest { testcases default-extra-flags } {
+    global runtests
+
+    foreach test $testcases {
+	# look if this is dg-do-run test, in which case
+	# we cycle through the option list, otherwise we don't
+	if [expr [search_for $test "dg-do run"]] {
+	    set option_list $TORTURE_OPTIONS
+	} else {
+	    set option_list [list { -O } ]
+	}
+
+	set nshort [file tail [file dirname $test]]/[file tail $test]
+
+	foreach flags $option_list {
+	    verbose "Testing $nshort, $flags" 1
+	    dg-test $test $flags ${default-extra-flags}
+	}
+    }
+}
diff --git a/gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl b/gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl
new file mode 100644
index 0000000..0eafab3
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl
@@ -0,0 +1,32 @@
+;; { dg-do compile { target aarch64-*-* } }
+;; { dg-options "-mtune=cortex-a53 -fsingle-pass=rtl-combine -fdump-rtl-combine" }
+
+;; Taken from
+;;    gcc/testsuite/gcc.dg/asr_div1.c -O2 -fdump-rtl-all -mtune=cortex-a53
+;; for aarch64, hand editing the prev/next insns to 0 as needed, and
+;; editing whitespace to avoid over-long lines.  */
+
+(function "f1"
+  (insn-chain
+
+(insn 8 0 9 2 (set (reg:DI 78)
+        (lshiftrt:DI (reg:DI 76)
+            (const_int 32 [0x20])))
+        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14
+        641 {*aarch64_lshr_sisd_or_int_di3}
+     (expr_list:REG_DEAD (reg:DI 76)
+        (nil)))
+(insn 9 8 0 2 (set (reg:SI 79)
+        (ashiftrt:SI (subreg:SI (reg:DI 78) 0)
+            (const_int 3 [0x3])))
+        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14
+        642 {*aarch64_ashr_sisd_or_int_si3}
+     (expr_list:REG_DEAD (reg:DI 78)
+        (nil)))
+
+  ) ;; insn-chain
+) ;; function
+
+;; Verify that insns 8 and 9 get combined into a shift of 35 (0x23)
+;; { dg-final { scan-rtl-dump "allowing combination of insns 8 and 9" "combine" } }
+;; { dg-final { scan-rtl-dump "modifying insn i3     9: r79:SI#0=r76:DI>>0x23" "combine" } }
diff --git a/gcc/testsuite/rtl.dg/aarch64/pr71779.rtl b/gcc/testsuite/rtl.dg/aarch64/pr71779.rtl
new file mode 100644
index 0000000..96f6e3d
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/aarch64/pr71779.rtl
@@ -0,0 +1,44 @@
+;; { dg-do compile { target aarch64-*-* } }
+;; { dg-options "-fsingle-pass=rtl-cse1 -fdump-rtl-cse1" }
+
+;; Dump taken from comment 2 of PR 71779, of
+;; "...the relevant memory access coming out of expand"
+;; with basic block IDs added, and prev/next insns set to
+;; 0 at ends, and 'p' added to pseudo regnos.
+
+(function "fragment"
+  (insn-chain
+
+;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
+(insn 1045 0 1046 2 (set (reg:SI 480)
+        (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
+                    [flags 0xc0]
+                    <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+     y.c:12702 -1
+     (nil))
+(insn 1046 1045 1047 2 (set (reg/f:SI 479)
+        (lo_sum:SI (reg:SI 480)
+            (symbol_ref:SI ("isl_obj_map_vtable")
+               [flags 0xc0]
+               <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+     y.c:12702 -1
+     (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
+                             [flags 0xc0]
+                             <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)
+        (nil)))
+(insn 1047 1046 1048 2 (set (reg:DI 481)
+        (subreg:DI (reg/f:SI 479) 0)) y.c:12702 -1
+     (nil))
+(insn 1048 1047 1049 2 (set (zero_extract:DI (reg/v:DI 191 [ obj1D.17368 ])
+            (const_int 32 [0x20])
+            (const_int 0 [0]))
+        (reg:DI 481)) y.c:12702 -1
+     (nil))
+;; Extra insn, to avoid all of the above from being deleted by DCE
+(insn 1049 1048 0 2 (set (mem:DI (reg:DI 191) [1 i+0 S4 A32])
+                         (const_int 1 [0x1])) -1 (nil))
+
+  ) ;; insn-chain
+) ;; function
+
+;; TODO: scan the dump
diff --git a/gcc/testsuite/rtl.dg/cfg-extra-bb.rtl b/gcc/testsuite/rtl.dg/cfg-extra-bb.rtl
new file mode 100644
index 0000000..7da8870
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/cfg-extra-bb.rtl
@@ -0,0 +1,12 @@
+(function "extra_bb"
+  (insn-chain) ;; empty
+  (cfg
+     (bb 0 ;; entry
+       (edge 0 2 (flags 0x1)) ;; { dg-error "bb index 2 not referenced by insns" }
+     ) ;; bb
+     (bb 2
+       (edge 2 1 (flags 0x1))
+     ) ;; bb
+     (bb 1) ;; exit
+  ) ;; cfg
+)
diff --git a/gcc/testsuite/rtl.dg/cfg-missing-bb.rtl b/gcc/testsuite/rtl.dg/cfg-missing-bb.rtl
new file mode 100644
index 0000000..cd82d04
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/cfg-missing-bb.rtl
@@ -0,0 +1,16 @@
+(function "missing_bb"
+  (insn-chain
+    (note 2 0 3 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+    (note 3 2 0 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
+  ) ;; empty
+  (cfg ;; { dg-error "bb index 3 used in .insn-chain. but not listed in .cfg." }
+       ;; { dg-error "1 missing bb.s." "" { target *-*-*} 6 }
+     (bb 0 ;; entry
+       (edge 0 2 (flags 0x1))
+     ) ;; bb
+     (bb 2
+       (edge 2 1 (flags 0x1))
+     ) ;; bb
+     (bb 1) ;; exit
+  ) ;; cfg
+)
diff --git a/gcc/testsuite/rtl.dg/good-include.rtl b/gcc/testsuite/rtl.dg/good-include.rtl
new file mode 100644
index 0000000..24be829
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/good-include.rtl
@@ -0,0 +1,6 @@
+/* Verify that we can include fragments from another dump.
+   We give the included file a .md suffix to avoid it being
+   run by rtl.exp.  */
+
+(include "good-includee.md")
+/* TODO: verify that we have the instruction from the above file.  */
diff --git a/gcc/testsuite/rtl.dg/good-includee.md b/gcc/testsuite/rtl.dg/good-includee.md
new file mode 100644
index 0000000..3314c40
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/good-includee.md
@@ -0,0 +1,5 @@
+(function "test"
+  (insn-chain
+    (note 1 0 0 (nil) NOTE_INSN_DELETED)
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/rtl.dg/missing-include.rtl b/gcc/testsuite/rtl.dg/missing-include.rtl
new file mode 100644
index 0000000..f99f3ef
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/missing-include.rtl
@@ -0,0 +1 @@
+(include "does-not-exist.rtl") /* { dg-error "include file .does-not-exist.rtl. not found" } */
diff --git a/gcc/testsuite/rtl.dg/more-than-one-cfg.rtl b/gcc/testsuite/rtl.dg/more-than-one-cfg.rtl
new file mode 100644
index 0000000..7153e0f
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/more-than-one-cfg.rtl
@@ -0,0 +1,7 @@
+(function "more_than_one_cfg"
+  (insn-chain) ;; insn-chain
+
+  (cfg)
+  (cfg) ;; { dg-error "more than one 'cfg' directive" }
+
+) ;; function
diff --git a/gcc/testsuite/rtl.dg/rtl.exp b/gcc/testsuite/rtl.dg/rtl.exp
new file mode 100644
index 0000000..71bebb9
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/rtl.exp
@@ -0,0 +1,41 @@
+#   Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+# 
+# This program 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/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib rtl-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_RTLFLAGS
+if ![info exists DEFAULT_RTLFLAGS] then {
+    set DEFAULT_RTLFLAGS ""
+    # -fdump-tree-rtl-raw
+}
+
+# Initialize `dg'.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir *.rtl]]
+
+verbose "rtl.exp tests: $tests" 1
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_RTLFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/rtl.dg/test.c b/gcc/testsuite/rtl.dg/test.c
new file mode 100644
index 0000000..ebb8aef
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/test.c
@@ -0,0 +1,31 @@
+int test_1 (int i, int j, int k)
+{
+  if (i < j)
+    return k + 4;
+  else
+    return -k;
+}
+
+/* Example showing:
+   - data structure
+   - loop
+   - call to "abort".  */
+
+struct foo
+{
+  int count;
+  float *data;
+};
+
+float test_2 (struct foo *lhs, struct foo *rhs)
+{
+  float result = 0.0f;
+
+  if (lhs->count != rhs->count)
+    __builtin_abort ();
+
+  for (int i = 0; i < lhs->count; i++)
+    result += lhs->data[i] * rhs->data[i];
+
+  return result;
+}
diff --git a/gcc/testsuite/rtl.dg/unknown-insn-uid.rtl b/gcc/testsuite/rtl.dg/unknown-insn-uid.rtl
new file mode 100644
index 0000000..8e63ace
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/unknown-insn-uid.rtl
@@ -0,0 +1,6 @@
+(function "test"
+  (insn-chain
+    (note 6 1 0 2 [bb 2] NOTE_INSN_BASIC_BLOCK) ;; { dg-error "insn with UID 1 not found for operand 0 ..PREV_INSN.. of insn 6" }
+    (note 7 0 3 2 [bb 2] NOTE_INSN_BASIC_BLOCK) ;; { dg-error "insn with UID 3 not found for operand 1 ..NEXT_INSN.. of insn 7" }
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/rtl.dg/unknown-rtx-code.rtl b/gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
new file mode 100644
index 0000000..9930677
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
@@ -0,0 +1,5 @@
+(function "test"
+  (insn-chain
+    (not-a-valid-kind-of-insn 1 0 0) ;; { dg-error "unknown rtx code" }
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/rtl.dg/x86_64/dfinit.rtl b/gcc/testsuite/rtl.dg/x86_64/dfinit.rtl
new file mode 100644
index 0000000..54370a6
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/dfinit.rtl
@@ -0,0 +1,102 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-dfinit -fdump-rtl-dfinit" } */
+
+/* Lightly-modified dump of test.c.247r.split1 for x86_64, with
+   "function" directives added by hand.  */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(function "test_1"
+  (insn-chain
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 3 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 29 3 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 29 13 30 3 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 30 29 16)
+(code_label 16 30 17 4 2 (nil) [1 uses])
+(note 17 16 18 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 4 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 5 3 (nil) [1 uses])
+(note 21 20 22 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 5 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 5 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 5 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+) ;; insn-chain
+
+   (crtl
+     (return_rtx
+       (reg/i:SI 0 ax)
+     ) ;; return_rtx
+   ) ;; crtl
+
+) ;; function
+
+/* Verify that the dataflow information matches what cc1 would have
+   generated.  In particular, in earlier versions of the RTL
+   frontend, the exit block use of reg 0 (ax) wasn't picked up
+   on, due to not setting up crtl->return_rtx based on
+   DECL_RESULT (fndecl).  */
+/* { dg-final { scan-rtl-dump ";;  exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+/* { dg-final { scan-rtl-dump ";;  regs ever live.*0 .ax. 1 .dx. 4 .si. 5 .di. 17 .flags." "dfinit" } } */
diff --git a/gcc/testsuite/rtl.dg/x86_64/final.rtl b/gcc/testsuite/rtl.dg/x86_64/final.rtl
new file mode 100644
index 0000000..dbcdd0b
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/final.rtl
@@ -0,0 +1,58 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-final -fdump-rtl-final" } */
+
+/* Lightly-modified dump of test.c.289r.dwarf2 for x86_64 target.  */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(function "test_1"
+  (insn-chain
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 32 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(note 32 6 5 2 NOTE_INSN_PROLOGUE_END)
+(note 5 32 31 2 NOTE_INSN_FUNCTION_BEG)
+(insn:TI 31 5 27 2 (set (reg:SI 0 ax [93])
+        (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+            (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 27 31 28 2 (parallel [
+            (set (reg:SI 1 dx [92])
+                (neg:SI (reg/v:SI 1 dx [orig:90 k ] [90])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_UNUSED (reg:CC 17 flags)
+        (nil)))
+(insn 28 27 29 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg/v:SI 5 di [orig:88 i ] [88])
+            (reg/v:SI 4 si [orig:89 j ] [89]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_DEAD (reg/v:SI 5 di [orig:88 i ] [88])
+        (expr_list:REG_DEAD (reg/v:SI 4 si [orig:89 j ] [89])
+            (nil))))
+(insn:TI 29 28 23 2 (set (reg:SI 0 ax [orig:87 <retval> ] [87])
+        (if_then_else:SI (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (reg:SI 1 dx [92])
+            (reg:SI 0 ax [93]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_DEAD (reg:CCGC 17 flags)
+        (expr_list:REG_DEAD (reg:SI 1 dx [92])
+            (nil))))
+(insn 23 29 34 2 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(jump_insn:TI 34 23 33 2 (simple_return) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil)
+ -> simple_return)
+(barrier 33 34 30)
+(note 30 33 0 (nil) NOTE_INSN_DELETED)
+
+  ) ;; insn-chain
+) ;; function
+
+/* Verify that asm was emitted.  */
+/* { dg-final { scan-assembler "test_1:" } } */
+/* { dg-final { scan-assembler ".cfi_startproc" } } */
+/* { dg-final { scan-assembler ".cfi_endproc" } } */
+
+/* Verify that the "simple_return" was recognized.
+   FIXME: this assumes i386.md.  */
+/* { dg-final { scan-assembler "ret" } } */
diff --git a/gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl b/gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl
new file mode 100644
index 0000000..f7798aa
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl
@@ -0,0 +1,91 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-into_cfglayout -fdump-rtl-into_cfglayout" } */
+
+(function "test"
+  (insn-chain
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 4 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 14 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 14 13 15 4 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 15 14 16)
+(code_label 16 15 17 5 2 (nil) [1 uses])
+(note 17 16 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 5 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 5 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 6 3 (nil) [1 uses])
+(note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 6 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 6 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+) ;; insn-chain
+) ;; function
+
+/* The conversion to cfglayout should eliminate unconditional jump
+   instructions...  */
+/* { dg-final { scan-rtl-dump "Removing jump 14." "into_cfglayout" } }  */
+/* { dg-final { scan-rtl-dump-not "jump_insn 14" "into_cfglayout" } }  */
+/* { dg-final { scan-rtl-dump-not "barrier 15" "into_cfglayout" } }  */
+
+/* ...but conditional jumps should be preserved.  */
+/* { dg-final { scan-rtl-dump "jump_insn 10" "into_cfglayout" } }  */
diff --git a/gcc/testsuite/rtl.dg/x86_64/ira.rtl b/gcc/testsuite/rtl.dg/x86_64/ira.rtl
new file mode 100644
index 0000000..707895d
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/ira.rtl
@@ -0,0 +1,91 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-ira -fdump-rtl-ira" } */
+
+/* Lightly-modified dump of test.c.251r.asmcons for x86_64.  */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(function "test"
+(insn-chain
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 3 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 29 3 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 29 13 30 3 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 30 29 16)
+(code_label 16 30 17 4 2 (nil) [1 uses])
+(note 17 16 18 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 4 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 5 3 (nil) [1 uses])
+(note 21 20 22 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 5 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 5 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 5 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+
+) ;; insn-chain
+) ;; function
+
+/* Verify that IRA was run.  */
+/* { dg-final { scan-rtl-dump "Building IRA IR" "ira" } } */
diff --git a/gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl b/gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl
new file mode 100644
index 0000000..bfbe302
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl
@@ -0,0 +1,44 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-pro_and_epilogue -fdump-rtl-pro_and_epilogue" } */
+
+/* Lightly-modified dump of test.c.259r.split2 for x86_64.  */
+
+(function "test_1"
+(insn-chain
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 5 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(note 5 6 31 2 NOTE_INSN_FUNCTION_BEG)
+(insn 31 5 27 2 (set (reg:SI 0 ax [93])
+        (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+            (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 27 31 28 2 (parallel [
+            (set (reg:SI 1 dx [92])
+                (neg:SI (reg/v:SI 1 dx [orig:90 k ] [90])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 28 27 29 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg/v:SI 5 di [orig:88 i ] [88])
+            (reg/v:SI 4 si [orig:89 j ] [89]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 29 28 23 2 (set (reg:SI 0 ax [orig:87 <retval> ] [87])
+        (if_then_else:SI (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (reg:SI 1 dx [92])
+            (reg:SI 0 ax [93]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 23 29 30 2 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(note 30 23 0 (nil) NOTE_INSN_DELETED)
+
+) ;; insn-chain
+) ;; function
+
+/* Verify that the prologue and epilogue were added.  */
+/* { dg-final { scan-rtl-dump-times "NOTE_INSN_PROLOGUE_END" 1 "pro_and_epilogue" } }  */
+
+/* We expect a jump_insn to "simple_return".  */
+/* { dg-final { scan-rtl-dump-times "simple_return" 2 "pro_and_epilogue" } }  */
+
diff --git a/gcc/testsuite/rtl.dg/x86_64/vregs.rtl b/gcc/testsuite/rtl.dg/x86_64/vregs.rtl
new file mode 100644
index 0000000..95f5310
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/vregs.rtl
@@ -0,0 +1,88 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-vregs -fdump-rtl-vregs" } */
+
+(function "test"
+(insn-chain
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 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 ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 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])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 4 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 14 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 14 13 15 4 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 15 14 16)
+(code_label 16 15 17 5 2 (nil) [1 uses])
+(note 17 16 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 5 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 5 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 6 3 (nil) [1 uses])
+(note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 6 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 6 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+
+) ;; insn-chain
+) ;; function
+
+/* The 9 instances of "virtual-stack-vars" should now all be "frame".  */
+/* { dg-final { scan-rtl-dump-times "frame" 9 "vregs" } }  */
+/* { dg-final { scan-rtl-dump-not "virtual-stack-vars" "vregs" } }  */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 5f80763..2bb42a1 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -477,6 +477,13 @@ compile_file (void)
 
   if (flag_syntax_only || flag_wpa)
     return;
+
+  /* The RTL frontend is currently only capable of running one pass; this
+     is done from within the parse_file langhook.
+     Hence we must return early here.  Fixing this would require
+     being able to run passes from a certain point onwards.  */
+  if (in_rtl_frontend_p)
+    return;
  
   /* Reset maximum_field_alignment, it can be adjusted by #pragma pack
      and this shouldn't influence any types built by the middle-end
-- 
1.8.5.3

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

* [PATCH 10/16] Introduce class function_reader (v3)
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (6 preceding siblings ...)
  2016-10-05 15:45 ` [PATCH 12/16] combine.c selftests (v2) David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-05 16:00   ` Bernd Schmidt
  2016-10-05 15:45 ` [PATCH 05/16] Introduce rtl_data::init_stack_alignment David Malcolm
                   ` (7 subsequent siblings)
  15 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

This patch implements class function_reader, which implements
the dump-parsing functionality used in the rest of the kit.

Changed in v3:
* rather than hardcoding the selftest input dumps as escaped C strings
in the source code, move them out into separate files, using
selftest::locate_file
* update to use the new "print_rtx_function" output format, parsing
"(cfg)" and "(crtl)" directives to reconstruct the CFG and various
metadata.
* eliminated regno_remapper in favor of using the absence of a trailing
register name to detect pseudos
* significantly cleaner handling of print_rtx's various "warts",
moving the parsing from read-rtl.c to read-rtl-function.c, by making
read_rtx_operand virtual.  Split the implementation up into smaller
functions to make it easier to grok.
* more test coverage
* lots of other cleanups
(some FIXMEs and TODOs remain)

Blurb from original version:

This patch generalizes the RTL-reading capabilities so that they
can be run on the host as well as the build machine.
The available rtx in rtl.def changes dramatically between these
two configurations, so a fair amount of #ifdef GENERATOR_FILE is
required to express this.

This patch introduces a function_reader subclass of rtx_reader,
capable of reading an RTL function dump (or part of one),
reconstructing a cfun with a CFG and basic blocks containing insns.

gcc/ChangeLog:
	* Makefile.in (OBJS): Add errors.o, read-md.o, read-rtl.o,
	read-rtl-function.o, and selftest-rtl.o.
	* errors.c: Use consistent pattern for bconfig.h vs config.h
	includes.
	(progname): Wrap with #ifdef GENERATOR_FILE.
	(error): Likewise.  Add "error: " to message.
	(fatal): Likewise.
	(internal_error): Likewise.
	(trim_filename): Likewise.
	(fancy_abort): Likewise.
	* errors.h (struct file_location): Move here from read-md.h.
	(file_location::file_location): Likewise.
	(error_at): New decl.
	* function-tests.c (selftest::verify_three_block_rtl_cfg): Remove
	"static".
	* function.c (instantiate_decls): Guard call to
	instantiate_decls_1 with if (DECL_INITIAL (fndecl)).
	* print-rtl.c (print_rtx): Print "(nil)" rather than an empty
	string for NULL strings.  Print "(nil)" for NULL basic blocks.
	* read-md.c (read_skip_construct): Provide forward decl.
	(read_skip_spaces): Support '/'.
	(read_name): Rename to...
	(read_name_1): ...this new static function, adding "out_loc" param,
	and converting "missing name or number" to returning false, rather
	than failing.
	(read_name): Reimplement in terms of read_name_1.
	(read_name_or_nil): New function.
	(read_string): Handle "(nil)" by returning NULL.  */
	* read-md.h (struct file_location): Move to errors.h.
	(file_location::file_location): Likewise.
	Include errors.h.
	(rtx_reader::read_rtx_operand): Make virtual.
	(rtx_reader::read_until): New decl.
	(rtx_reader::handle_any_trailing_information): New virtual func.
	(rtx_reader::postprocess): New virtual func.
	(rtx_reader::m_in_call_function_usage): New field.
	(read_name): Convert return type from void to file_location.
	(read_name_or_nil): New decl.
	* read-rtl-function.c: New file.
	* read-rtl-function.h: New file.
	* read-rtl.c: Potentially include config.h rather than bconfig.h.
	For host, include function.h and emit-rtl.h.
	(apply_subst_iterator): Wrap with #ifdef GENERATOR_FILE.
	(bind_subst_iter_and_attr): Likewise.
	(add_condition_to_string): Likewise.
	(add_condition_to_rtx): Likewise.
	(apply_attribute_uses): Likewise.
	(add_current_iterators): Likewise.
	(apply_iterators): Likewise.
	(initialize_iterators): Guard usage of apply_subst_iterator with
	#ifdef GENERATOR_FILE.
	(read_conditions): Wrap with #ifdef GENERATOR_FILE.
	(read_mapping): Likewise.
	(add_define_attr_for_define_subst): Likewise.
	(add_define_subst_attr): Likewise.
	(read_subst_mapping): Likewise.
	(check_code_iterator): Likewise.
	(check_code_iterator): Likewise.
	(read_rtx): Likewise.  Move one-time initialization logic to...
	(one_time_initialization): New function.
	(rtx_reader::read_until): New method.
	(read_flags): New function.
	(parse_reg_note_name): New function.
	(rtx_reader::read_rtx_code): Initialize "iterator" to NULL.
	Call one_time_initialization.  Wrap iterator lookup within
	#ifdef GENERATOR_FILE.  Add parsing support for RTL dumps,
	mirroring the special-cases in print_rtx, by calling read_flags,
	reading REG_NOTE names, INSN_UID values, and calling
	handle_any_trailing_information.
	(rtx_reader::read_rtx_operand): Handle case 'e'.  When on host,
	reallocate XSTR and XTMPL fields in the GC-managed heap.
	(rtx_reader::read_nested_rtx): Call the postprocess vfunc on the
	return_rtx.
	(rtx_reader::rtx_reader): Initialize m_in_call_function_usage.
	* rtl.h (read_rtx): Wrap decl with #ifdef GENERATOR_FILE.
	* selftest-rtl.c: New file.
	* selftest-rtl.h: New file.
	* selftest-run-tests.c (selftest::run_tests): Run
	read_rtl_function_c_tests.
	* selftest.h  (selftest::read_rtl_function_c_tests): New decl.
	* tree-dfa.c (ssa_default_def): Return NULL_TREE for rtl function
	dumps.

gcc/testsuite/ChangeLog:
	* selftests: New subdirectory.
	* selftests/aarch64: New subdirectory.
	* selftests/aarch64/times-two.rtl: New file.
	* selftests/asr_div1.rtl: New file.
	* selftests/cfg-test.rtl: New file.
	* selftests/const-int.rtl: New file.
	* selftests/copy-hard-reg-into-frame.rtl: New file.
	* selftests/example-labels.rtl: New file.
	* selftests/insn-with-mode.rtl: New file.
	* selftests/jump-to-label-ref.rtl: New file.
	* selftests/jump-to-return.rtl: New file.
	* selftests/jump-to-simple-return.rtl: New file.
	* selftests/note-insn-deleted.rtl: New file.
	* selftests/note_insn_basic_block.rtl: New file.
	* selftests/symbol-ref.rtl: New file.
	* selftests/test-regno-renumbering.rtl: New file.
	* selftests/x86_64: New subdirectory.
	* selftests/x86_64/call-insn.rtl: New file.
	* selftests/x86_64/times-two.rtl: New file.
---
 gcc/Makefile.in                                    |    5 +
 gcc/errors.c                                       |   23 +-
 gcc/errors.h                                       |   14 +
 gcc/function-tests.c                               |    2 +-
 gcc/function.c                                     |    3 +-
 gcc/print-rtl.c                                    |    4 +-
 gcc/read-md.c                                      |   52 +-
 gcc/read-md.h                                      |   27 +-
 gcc/read-rtl-function.c                            | 2402 ++++++++++++++++++++
 gcc/read-rtl-function.h                            |   37 +
 gcc/read-rtl.c                                     |  205 +-
 gcc/rtl.h                                          |    2 +
 gcc/selftest-rtl.c                                 |   90 +
 gcc/selftest-rtl.h                                 |   67 +
 gcc/selftest-run-tests.c                           |    1 +
 gcc/selftest.h                                     |    1 +
 gcc/testsuite/selftests/aarch64/times-two.rtl      |   42 +
 gcc/testsuite/selftests/asr_div1.rtl               |   23 +
 gcc/testsuite/selftests/cfg-test.rtl               |   38 +
 gcc/testsuite/selftests/const-int.rtl              |   16 +
 .../selftests/copy-hard-reg-into-frame.rtl         |   12 +
 gcc/testsuite/selftests/example-labels.rtl         |    6 +
 gcc/testsuite/selftests/insn-with-mode.rtl         |    5 +
 gcc/testsuite/selftests/jump-to-label-ref.rtl      |   11 +
 gcc/testsuite/selftests/jump-to-return.rtl         |   10 +
 gcc/testsuite/selftests/jump-to-simple-return.rtl  |   11 +
 gcc/testsuite/selftests/note-insn-deleted.rtl      |    5 +
 gcc/testsuite/selftests/note_insn_basic_block.rtl  |    5 +
 gcc/testsuite/selftests/symbol-ref.rtl             |    7 +
 gcc/testsuite/selftests/test-regno-renumbering.rtl |    6 +
 gcc/testsuite/selftests/x86_64/call-insn.rtl       |   12 +
 gcc/testsuite/selftests/x86_64/times-two.rtl       |   57 +
 gcc/tree-dfa.c                                     |    5 +
 33 files changed, 3165 insertions(+), 41 deletions(-)
 create mode 100644 gcc/read-rtl-function.c
 create mode 100644 gcc/read-rtl-function.h
 create mode 100644 gcc/selftest-rtl.c
 create mode 100644 gcc/selftest-rtl.h
 create mode 100644 gcc/testsuite/selftests/aarch64/times-two.rtl
 create mode 100644 gcc/testsuite/selftests/asr_div1.rtl
 create mode 100644 gcc/testsuite/selftests/cfg-test.rtl
 create mode 100644 gcc/testsuite/selftests/const-int.rtl
 create mode 100644 gcc/testsuite/selftests/copy-hard-reg-into-frame.rtl
 create mode 100644 gcc/testsuite/selftests/example-labels.rtl
 create mode 100644 gcc/testsuite/selftests/insn-with-mode.rtl
 create mode 100644 gcc/testsuite/selftests/jump-to-label-ref.rtl
 create mode 100644 gcc/testsuite/selftests/jump-to-return.rtl
 create mode 100644 gcc/testsuite/selftests/jump-to-simple-return.rtl
 create mode 100644 gcc/testsuite/selftests/note-insn-deleted.rtl
 create mode 100644 gcc/testsuite/selftests/note_insn_basic_block.rtl
 create mode 100644 gcc/testsuite/selftests/symbol-ref.rtl
 create mode 100644 gcc/testsuite/selftests/test-regno-renumbering.rtl
 create mode 100644 gcc/testsuite/selftests/x86_64/call-insn.rtl
 create mode 100644 gcc/testsuite/selftests/x86_64/times-two.rtl

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 4b50f0b..7c8df56 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1270,6 +1270,7 @@ OBJS = \
 	dwarf2cfi.o \
 	dwarf2out.o \
 	emit-rtl.o \
+	errors.o \
 	et-forest.o \
 	except.o \
 	explow.o \
@@ -1408,6 +1409,9 @@ OBJS = \
 	print-rtl-function.o \
 	print-tree.o \
 	profile.o \
+	read-md.o \
+	read-rtl.o \
+	read-rtl-function.o \
 	real.o \
 	realmpfr.o \
 	recog.o \
@@ -1435,6 +1439,7 @@ OBJS = \
 	sel-sched-ir.o \
 	sel-sched-dump.o \
 	sel-sched.o \
+	selftest-rtl.o \
 	selftest-run-tests.o \
 	sese.o \
 	shrink-wrap.o \
diff --git a/gcc/errors.c b/gcc/errors.c
index 468384c..8df94ab 100644
--- a/gcc/errors.c
+++ b/gcc/errors.c
@@ -21,18 +21,21 @@ along with GCC; see the file COPYING3.  If not see
    in the generator programs; the compiler has a more elaborate suite
    of diagnostic printers, found in diagnostic.c.  */
 
-#ifdef HOST_GENERATOR_FILE
-#include "config.h"
-#define GENERATOR_FILE 1
-#else
+/* This file is compiled twice: once for the generator programs
+   once for the compiler.  */
+#ifdef GENERATOR_FILE
 #include "bconfig.h"
+#else
+#include "config.h"
 #endif
 #include "system.h"
 #include "errors.h"
 
 /* Set this to argv[0] at the beginning of main.  */
 
+#ifdef GENERATOR_FILE
 const char *progname;
+#endif /* #ifdef GENERATOR_FILE */
 
 /* Starts out 0, set to 1 if error is called.  */
 
@@ -55,13 +58,15 @@ warning (const char *format, ...)
 
 /* Print an error message - we keep going but the output is unusable.  */
 
+#ifdef GENERATOR_FILE
+
 void
 error (const char *format, ...)
 {
   va_list ap;
 
   va_start (ap, format);
-  fprintf (stderr, "%s: ", progname);
+  fprintf (stderr, "%s: error: ", progname);
   vfprintf (stderr, format, ap);
   va_end (ap);
   fputc ('\n', stderr);
@@ -69,6 +74,7 @@ error (const char *format, ...)
   have_error = 1;
 }
 
+#endif /* #ifdef GENERATOR_FILE */
 
 /* Fatal error - terminate execution immediately.  Does not return.  */
 
@@ -78,7 +84,7 @@ fatal (const char *format, ...)
   va_list ap;
 
   va_start (ap, format);
-  fprintf (stderr, "%s: ", progname);
+  fprintf (stderr, "%s: error: ", progname);
   vfprintf (stderr, format, ap);
   va_end (ap);
   fputc ('\n', stderr);
@@ -87,6 +93,8 @@ fatal (const char *format, ...)
 
 /* Similar, but say we got an internal error.  */
 
+#ifdef GENERATOR_FILE
+
 void
 internal_error (const char *format, ...)
 {
@@ -127,8 +135,11 @@ trim_filename (const char *name)
 /* "Fancy" abort.  Reports where in the compiler someone gave up.
    This file is used only by build programs, so we're not as polite as
    the version in diagnostic.c.  */
+
 void
 fancy_abort (const char *file, int line, const char *func)
 {
   internal_error ("abort in %s, at %s:%d", func, trim_filename (file), line);
 }
+
+#endif /* #ifdef GENERATOR_FILE */
diff --git a/gcc/errors.h b/gcc/errors.h
index a6973f3..ebafa77 100644
--- a/gcc/errors.h
+++ b/gcc/errors.h
@@ -28,8 +28,22 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_ERRORS_H
 #define GCC_ERRORS_H
 
+/* Records a position in the file.  */
+struct file_location {
+  file_location () {}
+  file_location (const char *, int, int);
+
+  const char *filename;
+  int lineno;
+  int colno;
+};
+
+inline file_location::file_location (const char *filename_in, int lineno_in, int colno_in)
+: filename (filename_in), lineno (lineno_in), colno (colno_in) {}
+
 extern void warning (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
 extern void error (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
+extern void error_at (file_location, const char *, ...) ATTRIBUTE_PRINTF_2 ATTRIBUTE_COLD;
 extern void fatal (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
 extern void internal_error (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
 extern const char *trim_filename (const char *);
diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index 4152cd3..2235b4c 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -420,7 +420,7 @@ verify_three_block_gimple_cfg (function *fun)
 
 /* As above, but additionally verify the RTL insns are sane.  */
 
-static void
+void
 verify_three_block_rtl_cfg (function *fun)
 {
   verify_three_block_cfg (fun);
diff --git a/gcc/function.c b/gcc/function.c
index 94ed786..1614bee 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -1901,7 +1901,8 @@ instantiate_decls (tree fndecl)
     instantiate_decl_rtl (DECL_RTL (DECL_VALUE_EXPR (decl)));
 
   /* Now process all variables defined in the function or its subblocks.  */
-  instantiate_decls_1 (DECL_INITIAL (fndecl));
+  if (DECL_INITIAL (fndecl))
+    instantiate_decls_1 (DECL_INITIAL (fndecl));
 
   FOR_EACH_LOCAL_DECL (cfun, ix, decl)
     if (DECL_RTL_SET_P (decl))
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index a905127..a2cb69a 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -220,7 +220,7 @@ print_rtx (const_rtx in_rtx)
       string:
 
 	if (str == 0)
-	  fputs (" \"\"", outfile);
+	  fputs (" (nil)", outfile);
 	else
 	  fprintf (outfile, " (\"%s\")", str);
 	sawclose = 1;
@@ -586,6 +586,8 @@ print_rtx (const_rtx in_rtx)
 #ifndef GENERATOR_FILE
 	if (XBBDEF (in_rtx, i))
 	  fprintf (outfile, " %i", XBBDEF (in_rtx, i)->index);
+	else
+	  fprintf (outfile, " (nil)");
 #endif
 	break;
 
diff --git a/gcc/read-md.c b/gcc/read-md.c
index 9ffdb8e..b6bafe7 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -65,6 +65,8 @@ static htab_t md_constants;
 /* A table of enum_type structures, hashed by name.  */
 static htab_t enum_types;
 
+static void read_skip_construct (int depth, file_location loc);
+
 /* Given an object that starts with a char * name field, return a hash
    code for its name.  */
 
@@ -347,7 +349,7 @@ read_skip_spaces (void)
 	    if (c != '*')
 	      {
 		unread_char (c);
-		fatal_with_file_and_line ("stray '/' in file");
+		return '/';
 	      }
 
 	    prevc = 0;
@@ -446,8 +448,8 @@ peek_char (void)
 /* Read an rtx code name into NAME.  It is terminated by any of the
    punctuation chars of rtx printed syntax.  */
 
-void
-read_name (struct md_name *name)
+static bool
+read_name_1 (struct md_name *name, file_location *out_loc)
 {
   int c;
   size_t i;
@@ -485,8 +487,12 @@ read_name (struct md_name *name)
       c = read_char ();
     }
 
+  unread_char (c);
+  *out_loc = base_rtx_reader_ptr->get_current_location ();
+  read_char ();
+
   if (i == 0)
-    fatal_with_file_and_line ("missing name or number");
+    return false;
 
   name->buffer[i] = 0;
   name->string = name->buffer;
@@ -507,6 +513,36 @@ read_name (struct md_name *name)
 	}
       while (def);
     }
+
+  return true;
+}
+
+/* Read an rtx code name into NAME.  It is terminated by any of the
+   punctuation chars of rtx printed syntax.  */
+
+file_location
+read_name (struct md_name *name)
+{
+  file_location loc;
+  if (!read_name_1 (name, &loc))
+    fatal_with_file_and_line ("missing name or number");
+  return loc;
+}
+
+file_location
+read_name_or_nil (struct md_name *name)
+{
+  file_location loc;
+  if (!read_name_1 (name, &loc))
+    {
+      file_location loc = base_rtx_reader_ptr->get_current_location ();
+      read_skip_construct (0, loc);
+      /* Skip the ')'.  */
+      read_char ();
+      name->buffer[0] = 0;
+      name->string = name->buffer;
+    }
+  return loc;
 }
 
 /* Subroutine of the string readers.  Handles backslash escapes.
@@ -652,6 +688,14 @@ read_string (int star_if_braced)
 	obstack_1grow (&string_obstack, '*');
       stringbuf = read_braced_string ();
     }
+  else if (saw_paren && c == 'n')
+    {
+      /* Handle (nil) by returning NULL.  */
+      require_char ('i');
+      require_char ('l');
+      require_char_ws (')');
+      return NULL;
+    }
   else
     fatal_with_file_and_line ("expected `\"' or `{', found `%c'", c);
 
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 0701f35..4933912 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -21,19 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_READ_MD_H
 
 #include "obstack.h"
-
-/* Records a position in the file.  */
-struct file_location {
-  file_location () {}
-  file_location (const char *, int, int);
-
-  const char *filename;
-  int lineno;
-  int colno;
-};
-
-inline file_location::file_location (const char *filename_in, int lineno_in, int colno_in)
-: filename (filename_in), lineno (lineno_in), colno (colno_in) {}
+#include "errors.h"
 
 /* Holds one symbol or number in the .md file.  */
 struct md_name {
@@ -200,9 +188,17 @@ class rtx_reader : public base_rtx_reader
   ~rtx_reader ();
 
   rtx read_rtx_code (const char *);
-  rtx read_rtx_operand (rtx return_rtx, int idx);
+  virtual rtx read_rtx_operand (rtx return_rtx, int idx);
   rtx read_nested_rtx (void);
   rtx read_rtx_variadic (rtx);
+  char *read_until (const char *terminator_chars, bool consume_terminator);
+
+  virtual void handle_any_trailing_information (rtx) {}
+  virtual rtx postprocess (rtx x) { return x; }
+
+ protected:
+  /* Analogous to print-rtl.c's in_call_function_usage.  */
+  bool m_in_call_function_usage;
 };
 
 /* Global singleton; constrast with base_rtx_reader_ptr above.  */
@@ -247,7 +243,8 @@ extern int read_skip_spaces (void);
 extern void require_char (char expected);
 extern void require_char_ws (char expected);
 extern void require_word_ws (const char *expected);
-extern void read_name (struct md_name *);
+extern file_location read_name (struct md_name *);
+extern file_location read_name_or_nil (struct md_name *);
 extern char *read_quoted_string (void);
 extern char *read_string (int);
 extern int n_comma_elts (const char *);
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
new file mode 100644
index 0000000..0cd34d4
--- /dev/null
+++ b/gcc/read-rtl-function.c
@@ -0,0 +1,2402 @@
+/* read-rtl-function.c - Reader for RTL function dumps
+   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 "target.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "stor-layout.h"
+#include "debug.h"
+#include "convert.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "common/common-target.h"
+#include "read-md.h"
+#include <mpfr.h>
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "pass_manager.h"
+#include "toplev.h"
+#include "bitmap.h"
+#include "df.h"
+#include "regs.h"
+#include "varasm.h"
+#include "insn-addr.h"
+#include "read-rtl-function.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
+
+/* Forward decls.  */
+class function_reader;
+class fixup;
+
+/* Subclass of rtx_reader for reading function dumps.  */
+
+class function_reader : public rtx_reader
+{
+ public:
+  function_reader (function_reader_policy *policy);
+  ~function_reader ();
+
+  /* Overridden vfuncs of class base_rtx_reader.  */
+  void handle_unknown_directive (file_location, const char *) FINAL OVERRIDE;
+
+  /* Overridden vfuncs of class rtx_reader.  */
+  rtx read_rtx_operand (rtx return_rtx, int idx) FINAL OVERRIDE;
+  void handle_any_trailing_information (rtx return_rtx) FINAL OVERRIDE;
+  rtx postprocess (rtx) FINAL OVERRIDE;
+
+  int get_pseudo_offset () const { return m_pseudo_offset; }
+  rtx_insn **get_insn_by_uid (int uid);
+  tree parse_mem_expr (const char *desc);
+
+ private:
+  void parse_function ();
+  void create_function ();
+  void parse_insn_chain ();
+  void parse_insn (file_location loc, const char *name);
+  void create_cfg_and_basic_blocks ();
+  void parse_cfg (file_location loc);
+  void parse_bb ();
+  void parse_edge ();
+  void parse_crtl (file_location loc);
+
+  void read_rtx_operand_u (rtx return_rtx, int idx);
+  void read_rtx_operand_i_or_n (rtx return_rtx, int idx, char format_char);
+  rtx extra_parsing_for_operand_code_0 (rtx return_rtx, int idx);
+  rtx extra_parsing_for_operand_code_r (rtx return_rtx);
+
+  void add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+			   int insn_uid);
+
+  void add_fixup_bb (file_location loc, rtx insn,
+		     int operand_idx, int bb_idx);
+
+  void add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+					int operand_idx, int bb_idx);
+
+  void add_fixup_source_location (file_location loc, rtx insn,
+				  int operand_idx,
+				  const char *filename, int lineno);
+
+  void add_fixup_jump_label (file_location loc, rtx insn,
+			     int operand_idx,
+			     const char *label);
+
+  void add_fixup_expr (file_location loc, rtx x,
+		       const char *desc);
+
+  void add_fixup_pseudo (file_location loc, rtx x);
+
+  rtx consolidate_singletons (rtx x);
+  void maybe_read_location (int operand_idx, rtx insn);
+
+  void apply_fixups ();
+  void recreate_implicit_cfg_edges ();
+
+ private:
+  function_reader_policy *m_policy;
+  struct uid_hash : int_hash <int, -1, -2> {};
+  hash_map<uid_hash, rtx_insn *> m_insns_by_uid;
+  auto_vec<fixup *> m_fixups;
+  bitmap_obstack m_bitmap_obstack;
+  bitmap_head m_dumped_pseudos;
+  bitmap_head m_bb_indices_in_insns;
+  bitmap_head m_bb_indices_in_cfg;
+  rtx_insn *m_first_insn;
+  auto_vec<tree> m_fake_scope;
+  char *m_name;
+  bool m_have_cfg_directive;
+  bool m_have_crtl_directive;
+  int m_pseudo_offset;
+};
+
+/* Abstract base class for recording post-processing steps that must be
+   done after reading a .rtl file.  */
+
+class fixup
+{
+ public:
+  fixup (file_location loc, rtx x)
+    : m_loc (loc), m_rtx (x)
+  {}
+  virtual ~fixup () {}
+
+  virtual void apply (function_reader *reader) const = 0;
+
+ protected:
+  file_location m_loc;
+  rtx m_rtx;
+};
+
+/* An abstract subclass of fixup for post-processing steps that
+   act on a specific operand of a specific instruction.  */
+
+class operand_fixup : public fixup
+{
+ public:
+  operand_fixup (file_location loc, rtx insn, int operand_idx)
+    : fixup (loc, insn), m_operand_idx (operand_idx)
+  {}
+
+ protected:
+  int m_operand_idx;
+};
+
+/* A concrete subclass of operand_fixup: fixup an rtx_insn *
+   field (NEXT_INSN/PREV_INSN) based on an integer UID.  */
+
+class fixup_insn_uid : public operand_fixup
+{
+ public:
+  fixup_insn_uid (file_location loc, rtx insn, int operand_idx, int insn_uid)
+    : operand_fixup (loc, insn, operand_idx),
+      m_insn_uid (insn_uid)
+  {}
+
+  void apply (function_reader *reader) const;
+
+ private:
+  int m_insn_uid;
+};
+
+/* A concrete subclass of operand_fixup: fix up a basic_block
+   pointer field based on an integer block ID.  */
+
+class fixup_bb : public operand_fixup
+{
+ public:
+  fixup_bb (file_location loc, rtx insn, int operand_idx, int bb_idx)
+    : operand_fixup (loc, insn, operand_idx),
+      m_bb_idx (bb_idx)
+  {}
+
+  void apply (function_reader *reader) const;
+
+ private:
+  int m_bb_idx;
+};
+
+/* A concrete subclass of operand_fixup: fix up a
+   NOTE_INSN_BASIC_BLOCK based on an integer block ID.  */
+
+class fixup_note_insn_basic_block : public operand_fixup
+{
+ public:
+  fixup_note_insn_basic_block (file_location loc, rtx insn, int operand_idx,
+			       int bb_idx)
+    : operand_fixup (loc, insn, operand_idx),
+      m_bb_idx (bb_idx)
+  {}
+
+  void apply (function_reader *reader) const;
+
+ private:
+  int m_bb_idx;
+};
+
+/* A concrete subclass of operand_fixup: fix up the JUMP_LABEL
+   of an insn based on a label name.  */
+
+class fixup_jump_label : public operand_fixup
+{
+ public:
+  fixup_jump_label (file_location loc, rtx insn,
+		    int operand_idx,
+		    const char *label)
+    : operand_fixup (loc, insn, operand_idx),
+      m_label (xstrdup (label))
+  {}
+
+  ~fixup_jump_label () { free (m_label); }
+
+  void apply (function_reader *reader) const;
+
+ private:
+  char *m_label;
+};
+
+/* A concrete subclass of fixup (not operand_fixup): fix up
+   the expr of an rtx (REG or MEM) based on a textual dump.  */
+
+class fixup_expr : public fixup
+{
+ public:
+  fixup_expr (file_location loc, rtx x, const char *desc)
+    : fixup (loc, x),
+      m_desc (xstrdup (desc))
+  {}
+
+  ~fixup_expr () { free (m_desc); }
+
+  void apply (function_reader *reader) const;
+
+ private:
+  char *m_desc;
+};
+
+/* A concrete subclass of fixup (not operand_fixup): fix up
+   the regno of a pseudo REG to ensure that it is a pseudo
+   on the current target.  */
+
+class fixup_pseudo : public fixup
+{
+ public:
+  fixup_pseudo (file_location loc, rtx x)
+    : fixup (loc, x)
+  {}
+
+  void apply (function_reader *reader) const;
+};
+
+/* Return a textual description of the given operand of the given rtx.  */
+
+static const char *
+get_operand_name (rtx insn, int operand_idx)
+{
+  gcc_assert (is_a <rtx_insn *> (insn));
+  switch (operand_idx)
+    {
+    case 0:
+      return "PREV_INSN";
+    case 1:
+      return "NEXT_INSN";
+    default:
+      return NULL;
+    }
+}
+
+/* Fixup an rtx_insn * field (NEXT_INSN/PREV_INSN) based on an integer
+   UID.  */
+
+void
+fixup_insn_uid::apply (function_reader *reader) const
+{
+  rtx_insn **insn_from_uid = reader->get_insn_by_uid (m_insn_uid);
+  if (insn_from_uid)
+    XEXP (m_rtx, m_operand_idx) = *insn_from_uid;
+  else
+    {
+      const char *op_name = get_operand_name (m_rtx, m_operand_idx);
+      if (op_name)
+	error_at (m_loc,
+		  "insn with UID %i not found for operand %i (`%s') of insn %i",
+		  m_insn_uid, m_operand_idx, op_name, INSN_UID (m_rtx));
+      else
+	error_at (m_loc,
+		  "insn with UID %i not found for operand %i of insn %i",
+		  m_insn_uid, m_operand_idx, INSN_UID (m_rtx));
+    }
+}
+
+/* Fix up a basic_block pointer field based on an integer block ID.
+   Update BB_HEAD and BB_END of the block as appropriate, as if the insn
+   was being added to the end of the block.  */
+
+void
+fixup_bb::apply (function_reader */*reader*/) const
+{
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
+  gcc_assert (bb);
+  XBBDEF (m_rtx, m_operand_idx) = bb;
+
+  rtx_insn *insn = as_a <rtx_insn *> (m_rtx);
+  if (!BB_HEAD (bb))
+    BB_HEAD (bb) = insn;
+  BB_END (bb) = insn;
+}
+
+/* Fix up a NOTE_INSN_BASIC_BLOCK based on an integer block ID.  */
+
+void
+fixup_note_insn_basic_block::apply (function_reader */*reader*/) const
+{
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
+  gcc_assert (bb);
+  NOTE_BASIC_BLOCK (m_rtx) = bb;
+}
+
+/* Fix up the JUMP_LABEL of an insn based on a label name.  */
+
+void
+fixup_jump_label::apply (function_reader *reader) const
+{
+  if (0 == strcmp (m_label, "return"))
+    JUMP_LABEL (m_rtx) = ret_rtx;
+  else if (0 == strcmp (m_label, "simple_return"))
+    JUMP_LABEL (m_rtx) = simple_return_rtx;
+  else
+    {
+      int label_uid = atoi (m_label);
+      rtx_insn **insn_from_uid = reader->get_insn_by_uid (label_uid);
+      if (insn_from_uid)
+	JUMP_LABEL (m_rtx) = *insn_from_uid;
+      else
+	error_at (m_loc,
+		  "insn with UID %i not found for operand %i (`%s') of insn %i",
+		  label_uid, m_operand_idx, "JUMP_LABEL", INSN_UID (m_rtx));
+    }
+}
+
+/* Fix up the expr of an rtx (REG or MEM) based on a textual dump.  */
+
+void
+fixup_expr::apply (function_reader *reader) const
+{
+  tree expr = reader->parse_mem_expr (m_desc);
+  switch (GET_CODE (m_rtx))
+    {
+    case REG:
+      set_reg_attrs_for_decl_rtl (expr, m_rtx);
+      break;
+    case MEM:
+      set_mem_expr (m_rtx, expr);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+#if 0
+  if (!DECL_RTL_SET_P (expr))
+    SET_DECL_RTL (expr, m_rtx);
+#endif
+}
+
+/* Fix up the regno of a REG that ought to be a pseudo, based
+   on an offset generated from all of the pseudo regnos seen.  */
+
+void
+fixup_pseudo::apply (function_reader *reader) const
+{
+  gcc_assert (GET_CODE (m_rtx) == REG);
+
+  int dumped_regno = REGNO (m_rtx);
+  int effective_regno = dumped_regno + reader->get_pseudo_offset ();
+  set_regno_raw (m_rtx, effective_regno, 1);
+
+  ORIGINAL_REGNO (m_rtx) = effective_regno;
+  // FIXME: do we want this? it makes comparing dumps easier
+}
+
+/* Strip trailing whitespace from DESC.  */
+
+static void
+strip_trailing_whitespace (char *desc)
+{
+  char *terminator = desc + strlen (desc);
+  while (desc < terminator)
+    {
+      terminator--;
+      if (ISSPACE (*terminator))
+	*terminator = '\0';
+      else
+	break;
+    }
+}
+
+/* Return the numeric value n for GET_NOTE_INSN_NAME (n) for STRING,
+   or fail if STRING isn't recognized.  */
+
+static int
+parse_note_insn_name (const char *string)
+{
+  for (int i = 0; i < NOTE_INSN_MAX; i++)
+    if (0 == strcmp (string, GET_NOTE_INSN_NAME (i)))
+      return i;
+  fatal_with_file_and_line ("unrecognized NOTE_INSN name: `%s'", string);
+}
+
+/* Return the register number for NAME, or return -1 if it isn't
+   recognized.  */
+
+static int
+lookup_reg_by_dump_name (const char *name)
+{
+  for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (reg_names[i][0]
+	&& ! strcmp (name, reg_names[i]))
+      return i;
+
+  /* Also lookup virtuals.  */
+  if (!strcmp (name, "virtual-incoming-args"))
+    return VIRTUAL_INCOMING_ARGS_REGNUM;
+  if (!strcmp (name, "virtual-stack-vars"))
+    return VIRTUAL_STACK_VARS_REGNUM;
+  if (!strcmp (name, "virtual-stack-dynamic"))
+    return VIRTUAL_STACK_DYNAMIC_REGNUM;
+  if (!strcmp (name, "virtual-outgoing-args"))
+    return VIRTUAL_OUTGOING_ARGS_REGNUM;
+  if (!strcmp (name, "virtual-cfa"))
+    return VIRTUAL_CFA_REGNUM;
+  if (!strcmp (name, "virtual-preferred-stack-boundary"))
+    return VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM;
+  /* TODO: handle "virtual-reg-%d".  */
+
+  /* Not found.  */
+  return -1;
+}
+
+/* class function_reader : public rtx_reader */
+
+/* function_reader's constructor.  */
+
+function_reader::function_reader (function_reader_policy *policy)
+: rtx_reader (),
+  m_policy (policy),
+  m_first_insn (NULL),
+  m_name (NULL),
+  m_have_cfg_directive (false),
+  m_have_crtl_directive (false),
+  m_pseudo_offset (0)
+{
+  bitmap_obstack_initialize (&m_bitmap_obstack);
+  bitmap_initialize (&m_dumped_pseudos, &m_bitmap_obstack);
+  bitmap_initialize (&m_bb_indices_in_insns, &m_bitmap_obstack);
+  bitmap_initialize (&m_bb_indices_in_cfg, &m_bitmap_obstack);
+  bitmap_set_bit (&m_bb_indices_in_insns, ENTRY_BLOCK);
+  bitmap_set_bit (&m_bb_indices_in_insns, EXIT_BLOCK);
+}
+
+/* function_reader's destructor.  */
+
+function_reader::~function_reader ()
+{
+  int i;
+  fixup *f;
+  FOR_EACH_VEC_ELT (m_fixups, i, f)
+    delete f;
+
+  bitmap_obstack_release (&m_bitmap_obstack);
+
+  free (m_name);
+}
+
+/* Implementation of rtx_reader::handle_unknown_directive.
+
+   Require a top-level "function" elements, as emitted by
+   print_rtx_function, and parse it.  */
+
+void
+function_reader::handle_unknown_directive (file_location start_loc,
+					   const char *name)
+{
+  if (strcmp (name, "function"))
+    fatal_at (start_loc, "expected 'function'");
+
+  parse_function ();
+}
+
+/* Parse the output of print_rtx_function (or hand-written data in the
+   same format), having parsed the "(function"  heading, and finishing
+   immediately before the final ")".
+
+   The "cfg" and "crtl" clauses are optional.  */
+
+void
+function_reader::parse_function ()
+{
+  m_name = xstrdup (read_string (0));
+
+  create_function ();
+
+  require_char_ws ('(');
+  require_word_ws ("insn-chain");
+  parse_insn_chain ();
+
+  create_cfg_and_basic_blocks ();
+
+  while (1)
+    {
+      int c = read_skip_spaces ();
+      if (c == ')')
+	{
+	  unread_char (c);
+	  break;
+	}
+      unread_char (c);
+      require_char ('(');
+      file_location loc = get_current_location ();
+      struct md_name directive;
+      read_name (&directive);
+      if (strcmp (directive.string, "cfg") == 0)
+	parse_cfg (loc);
+      else if (strcmp (directive.string, "crtl") == 0)
+	parse_crtl (loc);
+      else
+	fatal_with_file_and_line ("missing 'cfg' or 'crtl'");
+    }
+
+  apply_fixups ();
+  if (!m_have_cfg_directive)
+    recreate_implicit_cfg_edges ();
+
+  /* Ensure x_cur_insn_uid is 1 more than the biggest insn UID seen.
+     This is normally updated by the various make_*insn_raw functions.  */
+  {
+    rtx_insn *insn;
+    int max_uid = 0;
+    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+      max_uid = MAX (max_uid, INSN_UID (insn));
+    crtl->emit.x_cur_insn_uid = max_uid + 1;
+  }
+
+  crtl->init_stack_alignment ();
+}
+
+/* Set up state for the function *before* fixups are applied.
+
+   Create "cfun" and a decl for the function.
+   By default, every function decl is hardcoded as
+      int test_1 (int i, int j, int k);
+   Set up various other state:
+   - the cfg and basic blocks (edges are created later, *after* fixups
+   are applied).
+   - add the function to the callgraph.  */
+
+void
+function_reader::create_function ()
+{
+  /* Currently we assume cfgrtl mode, rather than cfglayout mode.  */
+  if (0)
+    cfg_layout_rtl_register_cfg_hooks ();
+  else
+    rtl_register_cfg_hooks ();
+
+  /* Create cfun.  */
+  tree fn_name = get_identifier (m_name ? m_name : "test_1");
+  tree int_type = integer_type_node;
+  tree return_type = int_type;
+  tree arg_types[3] = {int_type, int_type, int_type};
+  tree fn_type = build_function_type_array (return_type, 3, arg_types);
+  tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+				 fn_type);
+  tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+			     return_type);
+  DECL_ARTIFICIAL (resdecl) = 1;
+  DECL_IGNORED_P (resdecl) = 1;
+  DECL_RESULT (fndecl) = resdecl;
+  allocate_struct_function (fndecl, false);
+  /* This sets cfun.  */
+
+  current_function_decl = fndecl;
+
+  cfun->curr_properties = (PROP_cfg | PROP_rtl);
+
+  /* Do we need this to force cgraphunit.c to output the function? */
+  DECL_EXTERNAL (fndecl) = 0;
+  DECL_PRESERVE_P (fndecl) = 1;
+
+  /* Add to cgraph.  */
+  {
+    /* cgraph_node::add_new_function does additional processing
+       based on symtab->state.  We need to avoid it attempting to gimplify
+       things.  Temporarily putting it in the PARSING state appears to
+       achieve this.  */
+    enum symtab_state old_state = symtab->state;
+    symtab->state = PARSING;
+    cgraph_node::add_new_function (fndecl, true /*lowered*/);
+    /* Reset the state.  */
+    symtab->state = old_state;
+  }
+}
+
+/* Parse zero or more child insn elements within an
+   "insn-chain" element.  */
+
+void
+function_reader::parse_insn_chain ()
+{
+  while (1)
+    {
+      int c = read_skip_spaces ();
+      file_location loc = get_current_location ();
+      if (c == ')')
+	break;
+      else if (c == '(')
+	{
+	  struct md_name directive;
+	  read_name (&directive);
+	  parse_insn (loc, directive.string);
+	  require_char_ws (')');
+	}
+      else
+	fatal_at (loc, "expected '(' or ')'");
+    }
+}
+
+/* Parse rtx instructions by calling read_rtx_code, calling
+   set_first_insn and set_last_insn as appropriate.  */
+
+void
+function_reader::parse_insn (file_location start_loc, const char *name)
+{
+  rtx x = read_rtx_code (name);
+  if (!x)
+    fatal_at (start_loc, "expected insn type; got '%s'", name);
+  rtx_insn *insn = as_a <rtx_insn *> (x);
+  set_last_insn (insn);
+  if (!m_first_insn)
+    {
+      m_first_insn = insn;
+      set_first_insn (insn);
+    }
+  m_insns_by_uid.put (INSN_UID (insn), insn);
+}
+
+/* Create cfun's CFG and populate with blocks, a helper
+   function for function_reader::parse_function ().
+
+   The edges are created later on, either by parsing "edge" directives
+   in the input file, or implicity from the insns, after fixups are applied.
+
+   We can't call create_basic_block and use the regular RTL block-creation
+   hooks, since this creates NOTE_INSN_BASIC_BLOCK instances.  We don't
+   want to do that; we want to use the notes we were provided with.
+
+   The term "index" has two meanings for basic blocks in a CFG:
+   (a) the "index" field within struct basic_block_def.
+   (b) the index of a basic_block within the cfg's x_basic_block_info
+   vector, as accessed via BASIC_BLOCK_FOR_FN.
+
+   These can get out-of-sync when basic blocks are optimized away.
+   They get back in sync by "compact_blocks".
+   We make the assumption that the CFG has been compacted, and
+   so we reconstruct cfun->cfg->x_basic_block_info->m_vecdata with NULL
+   values in it for any missing basic blocks, so that (a) == (b) for
+   all of the blocks we create.  The doubly-linked list of basic
+   blocks (next_bb/prev_bb) skips over these "holes".  */
+
+void
+function_reader::create_cfg_and_basic_blocks ()
+{
+  /* Create bare-bones cfg.  This creates the entry and exit blocks.  */
+  init_empty_tree_cfg_for_function (cfun);
+  ENTRY_BLOCK_PTR_FOR_FN (cfun)->flags |= BB_RTL;
+  EXIT_BLOCK_PTR_FOR_FN (cfun)->flags |= BB_RTL;
+
+  /* Ensure that the vector of basic_block pointers is big enough.  */
+  unsigned highest_bb_idx = bitmap_last_set_bit (&m_bb_indices_in_insns);
+  size_t new_size = highest_bb_idx + 1;
+  if (basic_block_info_for_fn (cfun)->length () < new_size)
+    vec_safe_grow_cleared (basic_block_info_for_fn (cfun), new_size);
+
+  /* Populate the vector.  */
+  unsigned bb_idx;
+  bitmap_iterator bi;
+  basic_block after = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+  gcc_assert (after);
+  EXECUTE_IF_SET_IN_BITMAP (&m_bb_indices_in_insns, 0, bb_idx, bi)
+    {
+      /* The entry and exit blocks were already created above.  */
+      if (bb_idx == ENTRY_BLOCK || bb_idx == EXIT_BLOCK)
+	{
+	  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_idx);
+	  init_rtl_bb_info (bb);
+	  continue;
+	}
+      basic_block bb = alloc_block ();
+      init_rtl_bb_info (bb);
+      bb->index = bb_idx;
+      bb->flags = BB_NEW | BB_RTL;
+      link_block (bb, after);
+
+      n_basic_blocks_for_fn (cfun)++;
+      SET_BASIC_BLOCK_FOR_FN (cfun, bb_idx, bb);
+      BB_SET_PARTITION (bb, BB_UNPARTITIONED);
+
+      /* Tag the block so that we know it has been used when considering
+	 other basic block notes.  */
+      bb->aux = bb;
+
+      after = bb;
+    }
+
+  last_basic_block_for_fn (cfun) = highest_bb_idx + 1;
+}
+
+/* Parse a "(cfg)" directive, having parsed the "(cfg" heading.
+   Consume the final ")".  */
+
+void
+function_reader::parse_cfg (file_location loc)
+{
+  if (m_have_cfg_directive)
+    error_at (loc, "more than one 'cfg' directive");
+  m_have_cfg_directive = true;
+
+  while (1)
+    {
+      int c = read_skip_spaces ();
+      file_location loc = get_current_location ();
+      if (c == ')')
+	break;
+      else if (c == '(')
+	{
+	  require_word_ws ("bb");
+	  parse_bb ();
+	}
+      else
+	fatal_at (loc, "expected '(' or ')'");
+    }
+
+  /* Creating the BBs is fiddly.  For now, we rely on
+     create_cfg_and_basic_blocks, which works purely on the
+     set of BB indexes seen within the insns.
+     Hence we error-check to make sure the BB indexes seen
+     in the (cfg) is the same.
+
+     parse_bb complains about BB indices seen in (bb) directives that
+     weren't seen within the (insn-chain).
+
+     Complain here about the opposite: BB indices that were in the
+     (insn-chain) that were not seen in the (cfg).  */
+  bitmap_head just_in_insns;
+  bitmap_initialize (&just_in_insns, &m_bitmap_obstack);
+  bitmap_and_compl (&just_in_insns, &m_bb_indices_in_insns,
+		    &m_bb_indices_in_cfg);
+  unsigned bb_idx;
+  bitmap_iterator bi;
+  int num_errors = 0;
+  EXECUTE_IF_SET_IN_BITMAP (&just_in_insns, 0, bb_idx, bi)
+    /* Don't worry about entry/exit.  */
+    if (bb_idx > 1)
+	{
+	  error_at (loc,
+		    "error: bb index %i used in (insn-chain)"
+		    " but not listed in (cfg)", bb_idx);
+	  num_errors++;
+	}
+  if (num_errors)
+    fatal_at (loc, "%i missing bb(s)", num_errors);
+}
+
+/* Parse a "(bb)" directive, having parsed the "(bb" heading.
+   Consume the final ")".  Call parse_edge on any "(edge)"
+   directives encountered.  Don't actually created basic blocks;
+   instead, verify that the BB indices correspond to
+   those seen in the insn chain.  */
+
+void
+function_reader::parse_bb ()
+{
+  struct md_name name;
+  file_location loc = read_name (&name);
+  int bb_idx = atoi (name.string);
+  if (0)
+    fprintf (stderr, "parse_bb: %i\n", bb_idx);
+  bitmap_set_bit (&m_bb_indices_in_cfg, bb_idx);
+
+  /* The bb should already have been created by
+     create_cfg_and_basic_blocks.  */
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_idx);
+  if (!bb)
+    fatal_at (loc, "error: bb index %i not referenced by insns", bb_idx);
+
+  /* Parse 0 or more edges.  */
+  while (1)
+    {
+      int c = read_skip_spaces ();
+      file_location loc = get_current_location ();
+      if (c == ')')
+	break;
+      else if (c == '(')
+	{
+	  require_word_ws ("edge");
+	  parse_edge ();
+	}
+      else
+	fatal_at (loc, "expected '(' or ')'");
+    }
+}
+
+/* Parse a "(edge)" directive, having parsed the "(edge" heading.
+   Consume the final ")".  Create the edge within the CFG.  */
+
+void
+function_reader::parse_edge ()
+{
+  struct md_name name;
+  file_location loc = read_name (&name);
+  int src_bb_idx = atoi (name.string);
+  loc = read_name (&name);
+  int dst_bb_idx = atoi (name.string);
+
+  /* Flags.  */
+  require_char_ws ('(');
+  require_word_ws ("flags");
+  struct md_name hexval;
+  read_name (&hexval);
+  int flags = strtol (hexval.string, NULL, 16);
+  require_char_ws (')');
+
+  require_char_ws (')');
+
+  if (0)
+    fprintf (stderr, "parse_edge: %i-> %i flags 0x%x \n",
+	     src_bb_idx, dst_bb_idx, flags);
+
+  /* The BBs should already have been created by
+     create_cfg_and_basic_blocks.  */
+  basic_block src = BASIC_BLOCK_FOR_FN (cfun, src_bb_idx);
+  if (!src)
+    fatal_at (loc, "error: bb index %i not referenced by insns", src_bb_idx);
+  basic_block dst = BASIC_BLOCK_FOR_FN (cfun, dst_bb_idx);
+  if (!dst)
+    fatal_at (loc, "error: bb index %i not referenced by insns", dst_bb_idx);
+  unchecked_make_edge (src, dst, flags);
+}
+
+/* Parse a "(crtl)" directive, having parsed the "(crtl" heading.
+   Consume the final ")".  */
+
+void
+function_reader::parse_crtl (file_location loc)
+{
+  if (m_have_crtl_directive)
+    error_at (loc, "more than one 'crtl' directive");
+  m_have_crtl_directive = true;
+
+  /* return_rtx.  */
+  require_char_ws ('(');
+  require_word_ws ("return_rtx");
+
+  require_char_ws ('(');
+  struct md_name directive;
+  read_name (&directive);
+  crtl->return_rtx
+    = consolidate_singletons (read_rtx_code (directive.string));
+  require_char_ws (')');
+
+  require_char_ws (')');
+
+  require_char_ws (')');
+}
+
+/* Overridden implementation of rtx_reader::read_rtx_operand for
+   function_reader, handling various extra data printed by print_rtx,
+   and sometimes calling the base class implementation.  */
+
+rtx
+function_reader::read_rtx_operand (rtx return_rtx, int idx)
+{
+  RTX_CODE code = GET_CODE (return_rtx);
+  const char *format_ptr = GET_RTX_FORMAT (code);
+  const char format_char = format_ptr[idx];
+  struct md_name name;
+
+  /* Override the regular parser for some format codes.  */
+  switch (format_char)
+    {
+    case 'e':
+      {
+	if (idx == 7 && CALL_P (return_rtx))
+	  {
+	    m_in_call_function_usage = true;
+	    return rtx_reader::read_rtx_operand (return_rtx, idx);
+	    m_in_call_function_usage = false;
+	  }
+	else
+	  return rtx_reader::read_rtx_operand (return_rtx, idx);
+      }
+      break;
+
+    case 'u':
+      read_rtx_operand_u (return_rtx, idx);
+      /* Don't run regular parser for 'u'.  */
+      return return_rtx;
+
+    case 'i':
+    case 'n':
+      read_rtx_operand_i_or_n (return_rtx, idx, format_char);
+      /* Don't run regular parser for these codes.  */
+      return return_rtx;
+
+    case 'B':
+      {
+	file_location loc = read_name_or_nil (&name);
+	int bb_idx = atoi (name.string);
+	if (bb_idx)
+	  add_fixup_bb (loc, return_rtx, idx, bb_idx);
+	/* Don't run regular parser.  */
+	return return_rtx;
+      }
+      break;
+
+    default:
+      break;
+    }
+
+  /* Call base class implementation.  */
+  return_rtx = rtx_reader::read_rtx_operand (return_rtx, idx);
+
+  /* Handle any additional parsing needed to handle what the dump
+     could contain.  */
+  switch (format_char)
+    {
+    case '0':
+      return extra_parsing_for_operand_code_0 (return_rtx, idx);
+
+    case 'w':
+      {
+	/* Strip away the redundant hex dump of the value.  */
+	require_char_ws ('[');
+	read_name (&name);
+	require_char_ws (']');
+      }
+      break;
+
+    case 'r':
+      return extra_parsing_for_operand_code_r (return_rtx);
+
+    default:
+      break;
+    }
+
+  return return_rtx;
+}
+
+/* Special-cased handling of code 'u' for reading function dumps.
+
+   The RTL file recorded the ID of an insn (or 0 for NULL); we
+   must store this as a pointer, but the insn might not have
+   been loaded yet.  Store the ID away for now, via a fixup.  */
+
+void
+function_reader::read_rtx_operand_u (rtx return_rtx, int idx)
+{
+  struct md_name name;
+  file_location loc = read_name (&name);
+  int insn_id = atoi (name.string);
+  if (insn_id)
+    add_fixup_insn_uid (loc, return_rtx, idx, insn_id);
+}
+
+/* Special-cased handling of codes 'i' and 'n' for reading function
+   dumps.  */
+
+void
+function_reader::read_rtx_operand_i_or_n (rtx return_rtx, int idx,
+					  char format_char)
+{
+  /* Handle some of the extra information that print_rtx
+     can write out for these cases.  */
+  /* print_rtx only writes out operand 5 for notes
+     for NOTE_KIND values NOTE_INSN_DELETED_LABEL
+     and NOTE_INSN_DELETED_DEBUG_LABEL.  */
+  if (idx == 5 && NOTE_P (return_rtx))
+    return;
+
+  if (idx == 4 && INSN_P (return_rtx))
+    {
+      maybe_read_location (idx, return_rtx);
+      return;
+    }
+
+  struct md_name name;
+  read_name (&name);
+  int value;
+  if (format_char == 'n')
+    value = parse_note_insn_name (name.string);
+  else
+    value = atoi (name.string);
+  XINT (return_rtx, idx) = value;
+
+  /* print-rtl.c prints the names of recognized insns, after
+     the insn code, wrapping them in braces.  Skip them,
+     and reset the insn code to be unrecognized, since insn
+     codes are likely to change every time the .md files
+     change.  */
+  if (idx == 5 && INSN_P (return_rtx) && format_char == 'i')
+    if (value >= 0)
+      {
+	/* Get the content within the braces, skipping the braces.  */
+	require_char_ws ('{');
+	char *dumped_insn_name = read_until ("}", true);
+	if (0)
+	  fprintf (stderr, "got insn name: '%s'\n", dumped_insn_name);
+	/* For now, ignore the dumped insn name.  */
+	free (dumped_insn_name);
+
+	/* Reset the insn to be unrecognized.  */
+	INSN_CODE (return_rtx) = -1;
+      }
+}
+
+/* Additional parsing for format code '0' in dumps, handling a variety
+   of special-cases in print_rtx.  */
+
+rtx
+function_reader::extra_parsing_for_operand_code_0 (rtx return_rtx, int idx)
+{
+  RTX_CODE code = GET_CODE (return_rtx);
+  int c;
+  struct md_name name;
+
+  if (idx == 1 && code == SYMBOL_REF)
+    {
+      /* Possibly wrote " [flags %#x]", SYMBOL_REF_FLAGS (in_rtx).  */
+      c = read_skip_spaces ();
+      if (c == '[')
+	{
+	  file_location loc = read_name (&name);
+	  if (strcmp (name.string, "flags"))
+	    error_at (loc, "was expecting `%s'", "flags");
+	  read_name (&name);
+	  SYMBOL_REF_FLAGS (return_rtx) = strtol (name.string, NULL, 16);
+
+	  /* We can't reconstruct SYMBOL_REF_BLOCK; set it to NULL.  */
+	  if (SYMBOL_REF_HAS_BLOCK_INFO_P (return_rtx))
+	    SYMBOL_REF_BLOCK (return_rtx) = NULL;
+
+	  require_char (']');
+	}
+      else
+	unread_char (c);
+
+      /* Possibly wrote:
+	 print_node_brief (outfile, "", SYMBOL_REF_DECL (in_rtx),
+			   dump_flags);  */
+      c = read_skip_spaces ();
+      if (c == '<')
+	{
+	  /* Skip the content for now.  */
+	  while (1)
+	    {
+	      char ch = read_char ();
+	      if (ch == '>')
+		break;
+	    }
+	}
+      else
+	unread_char (c);
+    }
+  else if (idx == 3 && code == NOTE)
+    {
+      /* Note-specific data appears for operand 3, which annoyingly
+	 is before the enum specifying which kind of note we have
+	 (operand 4).  */
+      c = read_skip_spaces ();
+      if (c == '[')
+	{
+	  /* Possibly data for a NOTE_INSN_BASIC_BLOCK, of the form:
+	     [bb %d].  */
+	  file_location bb_loc = read_name (&name);
+	  if (strcmp (name.string, "bb"))
+	    error_at (bb_loc, "was expecting `%s'", "bb");
+	  read_name (&name);
+	  int bb_idx = atoi (name.string);
+	  add_fixup_note_insn_basic_block (bb_loc, return_rtx, idx,
+					   bb_idx);
+	  require_char_ws (']');
+	}
+      else
+	unread_char (c);
+    }
+  else if (idx == 7 && JUMP_P (return_rtx))
+    {
+      c = read_skip_spaces ();
+      if (c != '-')
+	{
+	  unread_char (c);
+	  return return_rtx;
+	}
+      require_char ('>');
+      file_location loc = read_name (&name);
+      add_fixup_jump_label (loc, return_rtx, idx, name.string);
+    }
+
+  return return_rtx;
+}
+
+/* Additional parsing for format code 'r' in dumps: register numbers.
+   The initial number has already been parsed.  */
+
+rtx
+function_reader::extra_parsing_for_operand_code_r (rtx return_rtx)
+{
+  /* REGNO holds the number from the dump.  */
+  unsigned int dumped_regno = REGNO (return_rtx);
+
+  /* print_rtx will print a name for hard and virtual registers
+     after the register number, and no name for pseudos.
+
+     It will then print zero, one, or two sections marked by square
+     brackets.
+
+     - see if there's a name after the number.  If there is, assume a hard
+     or virtual reg, and try to parse the name:
+     - if the name is recognized, use the target's current number for that
+     name (future-proofing virtuals against .md changes)
+     - if the name is not recognized, issue a fatal error (it's probably a
+     typo, or maybe a backport from a future version of gcc, or a target
+     incompatibility)
+     - if there's no name, assume it's a pseudo.  Remap all pseudos in a
+     postprocessing phase to ensure that they *are* pseudos (even if the .md
+     has gained some hard regs in the meantime), leaving the numbering
+     untouched if possible (the common case).  */
+
+  int effective_regno;
+
+  int ch = read_skip_spaces ();
+  unread_char (ch);
+  if (ch != '[' && ch != ')')
+    {
+      struct md_name name;
+      file_location loc = read_name (&name);
+      int regno_by_name = lookup_reg_by_dump_name (name.string);
+      if (regno_by_name == -1)
+	fatal_at (loc, "unrecognized register: '%s'", name.string);
+      effective_regno = regno_by_name;
+    }
+  else
+    {
+      /* No reg name in dump: this was a pseudo.  */
+      bitmap_set_bit (&m_dumped_pseudos, dumped_regno);
+
+      /* For now, use the dumped regno, but potentially
+	 fix it up later.  */
+      effective_regno = dumped_regno;
+      add_fixup_pseudo (get_current_location (), return_rtx);
+    }
+
+  set_regno_raw (return_rtx, effective_regno, 1);
+
+  /* Consolidate singletons.  */
+  return_rtx = consolidate_singletons (return_rtx);
+
+  ORIGINAL_REGNO (return_rtx) = effective_regno;
+
+  /* Parse extra stuff at end of 'r'.
+     We may have zero, one, or two sections marked by square
+     brackets.  */
+  ch = read_skip_spaces ();
+  bool expect_original_regno = false;
+  if (ch == '[')
+    {
+      file_location loc = get_current_location ();
+      char *desc = read_until ("]", true);
+      strip_trailing_whitespace (desc);
+      const char *desc_start = desc;
+      /* If ORIGINAL_REGNO (rtx) != regno, we will have:
+	 "orig:%i", ORIGINAL_REGNO (rtx).
+	 Consume it, we don't set ORIGINAL_REGNO, since we can
+	 get that from the 2nd copy later.  */
+      if (0 == strncmp (desc, "orig:", 5))
+	{
+	  expect_original_regno = true;
+	  desc_start += 5;
+	  /* Skip to any whitespace following the integer.  */
+	  const char *space = strchr (desc_start, ' ');
+	  if (space)
+	    desc_start = space + 1;
+	}
+      /* Any remaining text may be the REG_EXPR.  Alternatively we have
+	 no REG_ATTRS, and instead we have ORIGINAL_REGNO.  */
+      if (ISDIGIT (*desc_start))
+	{
+	  /* Assume we have ORIGINAL_REGNO.  */
+	  ORIGINAL_REGNO (return_rtx) = atoi (desc_start);
+	}
+      else
+	{
+	  /* Assume we have REG_EXPR.  */
+	  add_fixup_expr (loc, return_rtx, desc_start);
+	}
+      free (desc);
+    }
+  else
+    unread_char (ch);
+  if (expect_original_regno)
+    {
+      require_char_ws ('[');
+      char *desc = read_until ("]", true);
+      ORIGINAL_REGNO (return_rtx) = atoi (desc);
+      free (desc);
+    }
+
+  return return_rtx;
+}
+
+/* Implementation of rtx_reader::handle_any_trailing_information.
+   Handle the various additional information that print-rtl.c can
+   write after the regular fields.  */
+
+void
+function_reader::handle_any_trailing_information (rtx return_rtx)
+{
+  struct md_name name;
+
+  switch (GET_CODE (return_rtx))
+    {
+      case MEM:
+	{
+	  int ch;
+	  require_char_ws ('[');
+	  read_name (&name);
+	  MEM_ALIAS_SET (return_rtx) = atoi (name.string);
+	  /* We have either a MEM_EXPR, or a space.  */
+	  if (peek_char () != ' ')
+	    {
+	      file_location loc = get_current_location ();
+	      char *desc = read_until (" +", false);
+	      add_fixup_expr (loc, consolidate_singletons (return_rtx), desc);
+	      free (desc);
+	    }
+	  else
+	    read_char ();
+
+	  /* We may optionally have '+' for MEM_OFFSET_KNOWN_P.  */
+	  ch = read_skip_spaces ();
+	  if (ch == '+')
+	    {
+	      read_name (&name);
+	      MEM_OFFSET_KNOWN_P (return_rtx) = 1;
+	      MEM_OFFSET (return_rtx) = atoi (name.string);
+	    }
+	  else
+	    unread_char (ch);
+
+	  /* Handle optional " S" for MEM_SIZE.  */
+	  ch = read_skip_spaces ();
+	  if (ch == 'S')
+	    {
+	      read_name (&name);
+	      MEM_SIZE (return_rtx) = atoi (name.string);
+	    }
+	  else
+	    unread_char (ch);
+
+	  /* Handle optional " A" for MEM_ALIGN.  */
+	  ch = read_skip_spaces ();
+	  if (ch == 'A' && peek_char () != 'S')
+	    {
+	      read_name (&name);
+	      MEM_ALIGN (return_rtx) = atoi (name.string);
+	    }
+
+	  /* Handle optional " AS" for MEM_ADDR_SPACE.  */
+	  ch = read_skip_spaces ();
+	  if (ch == 'A' && peek_char () == 'S')
+	    {
+	      read_char ();
+	      read_name (&name);
+	      MEM_ADDR_SPACE (return_rtx) = atoi (name.string);
+	    }
+	  else
+	    unread_char (ch);
+
+	  require_char (']');
+	}
+	break;
+
+      case CODE_LABEL:
+	{
+	  /* Parse LABEL_NUSES.  */
+	  require_char_ws ('[');
+	  read_name (&name);
+	  LABEL_NUSES (return_rtx) = atoi (name.string);
+	  require_word_ws ("uses");
+	  require_char_ws (']');
+	  /* TODO: parse LABEL_KIND.  */
+	  /* For now, skip until closing ')'.  */
+	  do
+	    {
+	      char ch = read_char ();
+	      if (ch == ')')
+		{
+		  unread_char (ch);
+		  break;
+		}
+	    }
+	  while (1);
+	}
+	break;
+
+      default:
+	break;
+    }
+}
+
+/* Parse a tree dump for MEM_EXPR and turn it back into a tree.
+   We handle "<retval>", but for anything else we "cheat" by building a
+   global VAR_DECL of type "int" with that name (returning the same global
+   for a name if we see the same name more than once).  */
+
+tree
+function_reader::parse_mem_expr (const char *desc)
+{
+  tree fndecl = cfun->decl;
+
+  if (0 == strcmp (desc, "<retval>"))
+    {
+      return DECL_RESULT (fndecl);
+    }
+
+  /* Search within function parms.  */
+  for (tree arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN (arg))
+    {
+      if (strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (arg))) == 0)
+	return arg;
+    }
+
+  /* Search within decls we already created.
+     FIXME: use a hash rather than linear search.  */
+  int i;
+  tree t;
+  FOR_EACH_VEC_ELT (m_fake_scope, i, t)
+    if (strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (t))) == 0)
+      return t;
+
+  /* Not found?  Create it.
+     This allows mimicing of real data but avoids having to specify
+     e.g. names of locals, params etc.
+     Though this way we don't know if we have a PARM_DECL vs a VAR_DECL,
+     and we don't know the types.  Fake it by making everything be
+     a VAR_DECL of "int" type.  */
+  t = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		  get_identifier (desc),
+		  integer_type_node);
+  m_fake_scope.safe_push (t);
+  return t;
+}
+
+/* Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+				     int insn_uid)
+{
+  m_fixups.safe_push (new fixup_insn_uid (loc, insn, operand_idx, insn_uid));
+}
+
+/* Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_bb (file_location loc, rtx insn, int operand_idx,
+			       int bb_idx)
+{
+  bitmap_set_bit (&m_bb_indices_in_insns, bb_idx);
+  m_fixups.safe_push (new fixup_bb (loc, insn, operand_idx, bb_idx));
+}
+
+/* Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+						  int operand_idx, int bb_idx)
+{
+  m_fixups.safe_push (new fixup_note_insn_basic_block (loc, insn, operand_idx,
+						       bb_idx));
+}
+
+/* Record the information for later post-processing.  */
+void
+function_reader::add_fixup_source_location (file_location, rtx,
+					    int, const char *, int)
+{
+  /* Empty for now.  */
+}
+
+/* Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_jump_label (file_location loc, rtx insn,
+				       int operand_idx,
+				       const char *label)
+{
+  m_fixups.safe_push (new fixup_jump_label (loc, insn, operand_idx, label));
+}
+
+/* Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_expr (file_location loc, rtx insn,
+				 const char *desc)
+{
+  gcc_assert (desc);
+  /* Fail early if the RTL reader erroneously hands us an int.  */
+  gcc_assert (!ISDIGIT (desc[0]));
+
+  m_fixups.safe_push (new fixup_expr (loc, insn, desc));
+}
+
+/* Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_pseudo (file_location loc, rtx x)
+{
+  m_fixups.safe_push (new fixup_pseudo (loc, x));
+}
+
+/* Helper function for consolidate_reg.  */
+
+static rtx
+lookup_global_register (int regno)
+{
+  /* We can't use a switch here, as some of the REGNUMs might not be constants
+     for some targets.  */
+  if (regno == STACK_POINTER_REGNUM)
+      return stack_pointer_rtx;
+  else if (regno ==  FRAME_POINTER_REGNUM)
+    return frame_pointer_rtx;
+  else if (regno == HARD_FRAME_POINTER_REGNUM)
+    return hard_frame_pointer_rtx;
+  else if (regno == ARG_POINTER_REGNUM)
+    return arg_pointer_rtx;
+  else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
+    return virtual_incoming_args_rtx;
+  else if (regno == VIRTUAL_STACK_VARS_REGNUM)
+    return virtual_stack_vars_rtx;
+  else if (regno == VIRTUAL_STACK_DYNAMIC_REGNUM)
+    return virtual_stack_dynamic_rtx;
+  else if (regno == VIRTUAL_OUTGOING_ARGS_REGNUM)
+    return virtual_outgoing_args_rtx;
+  else if (regno == VIRTUAL_CFA_REGNUM)
+    return virtual_cfa_rtx;
+  else if (regno == VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM)
+    return virtual_preferred_stack_boundary_rtx;
+#ifdef return_ADDRESS_POINTER_REGNUM
+  else if (regno == RETURN_ADDRESS_POINTER_REGNUM)
+    return return_address_pointer_rtx;
+#endif
+
+  return NULL;
+}
+
+/* Normally REG instances are created by gen_reg_rtx which updates
+   regno_reg_rtx, growing it as necessary.
+   The REG instances created from the dumpfile weren't created this
+   way, so we need to manually update regno_reg_rtx.  */
+
+static void
+ensure_regno (int regno)
+{
+  crtl->emit.ensure_regno_capacity (regno + 1);
+  gcc_assert (regno < crtl->emit.regno_pointer_align_length);
+
+  if (reg_rtx_no < regno + 1)
+    reg_rtx_no = regno + 1;
+}
+
+/* Helper function for consolidate_singletons, for handling REG instances.  */
+
+static rtx
+consolidate_reg (rtx x)
+{
+  gcc_assert (GET_CODE (x) == REG);
+
+  unsigned int regno = REGNO (x);
+
+  ensure_regno (regno);
+
+  /* Some register numbers have their rtx created in init_emit_regs
+     e.g. stack_pointer_rtx for STACK_POINTER_REGNUM.
+     Consolidate on this.  */
+  rtx global_reg = lookup_global_register (regno);
+  if (global_reg)
+    return global_reg;
+
+  /* Populate regno_reg_rtx if necessary.  */
+  if (regno_reg_rtx[regno] == NULL)
+    regno_reg_rtx[regno] = x;
+  /* Use it.  */
+  gcc_assert (GET_CODE (regno_reg_rtx[regno]) == REG);
+  gcc_assert (REGNO (regno_reg_rtx[regno]) == regno);
+  if (GET_MODE (x) == GET_MODE (regno_reg_rtx[regno]))
+    return regno_reg_rtx[regno];
+
+  return x;
+}
+
+/* When reading RTL function dumps, we must consolidate some
+   rtx so that we use singletons where singletons are expected
+   (e.g. we don't want multiple "(const_int 0 [0])" rtx, since
+   these are tested via pointer equality against const0_rtx.  */
+
+rtx
+function_reader::consolidate_singletons (rtx x)
+{
+  if (!x)
+    return x;
+
+ switch (GET_CODE (x))
+    {
+    /* FIXME: do we need to check for VOIDmode for these?  */
+    case PC: return pc_rtx;
+    case RETURN: return ret_rtx;
+    case SIMPLE_RETURN: return simple_return_rtx;
+    case CC0: return cc0_rtx;
+
+    case REG:
+      return consolidate_reg (x);
+
+    case CONST_INT:
+      return gen_rtx_CONST_INT (GET_MODE (x), INTVAL (x));
+
+    default:
+      break;
+    }
+
+  return x;
+}
+
+/* Implementation of rtx_reader::postprocess for reading function dumps.  */
+
+rtx
+function_reader::postprocess (rtx x)
+{
+  return consolidate_singletons (x);
+}
+
+/* Handle the optional location information written by print_rtx for
+   instructions.  Specifically, operand 4 of instructions (of type "i')
+   is printed thus:
+
+     if (INSN_HAS_LOCATION (in_insn))
+       {
+	 expanded_location xloc = insn_location (in_insn);
+	 fprintf (outfile, " %s:%i", xloc.file, xloc.line);
+       }
+
+    Hence we need to speculatively read a location of the form
+    " %s:%i", and unread the content if there wasn't one.
+
+    Assume that filenames can't contain whitespace, and can't
+    contain ':'.  */
+
+void
+function_reader::maybe_read_location (int operand_idx, rtx insn)
+{
+  file_location loc = get_current_location ();
+
+  /* Skip to first non-whitespace.  */
+  int ch = read_skip_spaces ();
+  auto_vec<char> buf;
+  buf.safe_push (ch);
+  while (1)
+    {
+      int ch = read_char ();
+      /* If we see a ':', assume we have a filename.  */
+      if (ch == ':')
+	{
+	  buf.safe_push ('\0');
+	  break;
+	}
+      buf.safe_push (ch);
+
+      /* If we see a space before ':', assume we don't have a
+	 filename.  */
+      if (ISSPACE (ch))
+	{
+	  while (!buf.is_empty ())
+	    unread_char (buf.pop ());
+	  return;
+	}
+    }
+  char *filename = buf.address ();
+  struct md_name name;
+  read_name (&name);
+
+  add_fixup_source_location (loc, insn, operand_idx,
+			     filename, atoi(name.string));
+}
+
+/* Apply all of the recorded fixups.  */
+
+void
+function_reader::apply_fixups ()
+{
+  /* Set up m_pseudo_offset so that the lowest REGNO seen for a pseudo in
+     the dump will be a pseudo after any fixup_pseudo instances are applied,
+     preferring to leave it as zero if possible (to avoid renumbering).  */
+  if (!bitmap_empty_p (&m_dumped_pseudos))
+    {
+      int lowest_pseudo_in_dump = bitmap_first_set_bit (&m_dumped_pseudos);
+      if (lowest_pseudo_in_dump < LAST_VIRTUAL_REGISTER + 1)
+	{
+	  m_pseudo_offset = (LAST_VIRTUAL_REGISTER + 1) - lowest_pseudo_in_dump;
+
+	  /* We may need to resize the regno-based arrays.  */
+	  int highest_pseudo_in_dump = bitmap_last_set_bit (&m_dumped_pseudos);
+	  int highest_effective_pseudo = highest_pseudo_in_dump + m_pseudo_offset;
+	  ensure_regno (highest_effective_pseudo);
+	}
+    }
+
+  int i;
+  fixup *f;
+  FOR_EACH_VEC_ELT (m_fixups, i, f)
+    f->apply (this);
+}
+
+/* Given a UID value, try to locate a pointer to the corresponding
+   rtx_insn *, or NULL if if can't be found.  */
+
+rtx_insn **
+function_reader::get_insn_by_uid (int uid)
+{
+  return m_insns_by_uid.get (uid);
+}
+
+/* Visit every LABEL_REF within JUMP_INSN, calling CB on it, providing it
+   with USER_DATA.
+   FIXME: is there a preexisting way to do this?  */
+
+static void
+for_each_label_ref (rtx_jump_insn *jump_insn,
+		    void (*cb) (rtx_jump_insn *jump_insn,
+				rtx label_ref,
+				void *user_data),
+		    void *user_data)
+{
+  if (any_condjump_p (jump_insn))
+    {
+      rtx label_ref = condjump_label (jump_insn);
+      cb (jump_insn, label_ref, user_data);
+      return;
+    }
+
+  if (simplejump_p (jump_insn))
+    {
+      rtx label_ref = SET_SRC (PATTERN (jump_insn));
+      cb (jump_insn, label_ref, user_data);
+      return;
+    }
+
+  rtx_jump_table_data *tablep;
+  if (tablejump_p (jump_insn, NULL, &tablep))
+    {
+      gcc_assert (tablep);
+      rtvec labels = tablep->get_labels ();
+      int i, veclen = GET_NUM_ELEM (labels);
+      for (i = 0; i < veclen; ++i)
+	{
+	  rtx label_ref = RTVEC_ELT (labels, i);
+	  cb (jump_insn, label_ref, user_data);
+	}
+      return;
+    }
+
+  if (ANY_RETURN_P (PATTERN (jump_insn)))
+    return;
+
+  /* TODO: something else?  */
+  gcc_unreachable ();
+}
+
+/* Create an edge from SRC to DST, with the given flags.  */
+
+static void
+add_edge (basic_block src, basic_block dst, int flags)
+{
+  if (0)
+    fprintf (stderr, "making edge %i->%i\n",
+	     src->index, dst->index);
+  unchecked_make_edge (src, dst, flags);
+}
+
+/* Edge-creation callback for function_reader::create_cfg_edges.  */
+
+static void
+add_edge_cb (rtx_jump_insn *jump_insn, rtx label_ref, void */*user_data*/)
+{
+  gcc_assert (jump_insn);
+  gcc_assert (label_ref);
+  rtx_insn *label_insn = as_a <rtx_insn *> (LABEL_REF_LABEL (label_ref));
+  add_edge (BLOCK_FOR_INSN (jump_insn), BLOCK_FOR_INSN (label_insn), 0);
+}
+
+/* Create edges within cfun's CFG, by examining instructions in the
+   basic blocks and reconstructing the edges accordingly.
+   This is done after fixups are applied, since the latter is responsible
+   for setting up BB_HEAD and BB_END within each basic block.
+
+   This assumes cfgrtl mode, in which the edges are implicit from
+   the jump instructions.  It won't work for cfglayout mode, which
+   represents unconditional jumps purely as edges within the CFG,
+   without instructions, and this information isn't (currently)
+   written out to dumps.  */
+
+void
+function_reader::recreate_implicit_cfg_edges ()
+{
+  /* Create edge from ENTRY_BLOCK to block of first insn.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+  add_edge (entry, entry->next_bb, EDGE_FALLTHRU);
+
+  /* Create other edges.
+
+     The edge from the block of last insn to EXIT_BLOCK is created
+     below, by fall-through from the end of its block.  */
+  basic_block bb;
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      if (!BB_HEAD (bb))
+	continue;
+      rtx_insn *end_insn = BB_END (bb);
+      if (rtx_jump_insn *jump_insn = dyn_cast <rtx_jump_insn *> (end_insn))
+	{
+	  if (0)
+	    fprintf (stderr, "bb %i ends in jump\n", bb->index);
+	  if (!any_uncondjump_p (end_insn))
+	    {
+	      /* Add fallthrough edge first.  */
+	      gcc_assert (bb->next_bb);
+	      add_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+	    }
+	  for_each_label_ref (jump_insn, add_edge_cb, NULL);
+	}
+      else
+	{
+	  if (0)
+	    fprintf (stderr, "bb %i ends in non-jump\n", bb->index);
+	  if (bb->next_bb != NULL)
+	    {
+	      /* Add fallthrough edge.  */
+	      gcc_assert (bb->next_bb);
+	      add_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+	    }
+	}
+    }
+}
+
+/* Run the RTL dump parser.  If OUT_PSEUDO_OFFSET is non-NULL,
+   write any offset applied to the regnos of pseudoes to
+   *OUT_PSEUDO_OFFSET.  */
+
+bool
+read_rtl_function_body (int argc, const char **argv,
+			bool (*parse_opt) (const char *),
+			function_reader_policy *policy,
+			int *out_pseudo_offset)
+{
+  initialize_rtl ();
+  init_emit ();
+  init_varasm_status ();
+
+  function_reader reader (policy);
+  if (!reader.read_md_files (argc, argv, parse_opt))
+    return false;
+
+  if (out_pseudo_offset)
+    *out_pseudo_offset = reader.get_pseudo_offset ();
+
+  return true;
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that the src and dest indices and flags of edge E are as
+   expected, using LOC as the effective location when reporting
+   failures.  */
+
+static void
+assert_edge_at (const location &loc, edge e, int expected_src_idx,
+		int expected_dest_idx, int expected_flags)
+{
+  ASSERT_EQ_AT (loc, expected_src_idx, e->src->index);
+  ASSERT_EQ_AT (loc, expected_dest_idx, e->dest->index);
+  ASSERT_EQ_AT (loc, expected_flags, e->flags);
+}
+
+/* Verify that the src and dest indices and flags of EDGE are as
+   expected.  */
+
+#define ASSERT_EDGE(EDGE, EXPECTED_SRC_IDX, EXPECTED_DEST_IDX,		\
+		    EXPECTED_FLAGS)					\
+  assert_edge_at (SELFTEST_LOCATION, EDGE, EXPECTED_SRC_IDX, \
+		  EXPECTED_DEST_IDX, EXPECTED_FLAGS)
+
+/* Verify that we can load RTL dumps.  */
+
+static void
+test_loading_dump_fragment_1 ()
+{
+  // TODO: filter on target?
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("asr_div1.rtl"));
+
+  /* Verify that the insns were loaded correctly.  */
+  rtx_insn *insn_8 = get_insns ();
+  ASSERT_TRUE (insn_8);
+  ASSERT_EQ (8, INSN_UID (insn_8));
+  ASSERT_EQ (INSN, GET_CODE (insn_8));
+  ASSERT_EQ (SET, GET_CODE (PATTERN (insn_8)));
+  ASSERT_EQ (NULL, PREV_INSN (insn_8));
+
+  rtx_insn *insn_9 = NEXT_INSN (insn_8);
+  ASSERT_TRUE (insn_9);
+  ASSERT_EQ (9, INSN_UID (insn_9));
+  ASSERT_EQ (INSN, GET_CODE (insn_9));
+  ASSERT_EQ (insn_8, PREV_INSN (insn_9));
+  ASSERT_EQ (NULL, NEXT_INSN (insn_9));
+
+  /* Verify that registers were remapped.  */
+  rtx insn_8_dest = SET_DEST (PATTERN (insn_8));
+  ASSERT_EQ (REG, GET_CODE (insn_8_dest));
+  ASSERT_EQ (t.effective_regno (78), REGNO (insn_8_dest));
+  rtx insn_8_src = SET_SRC (PATTERN (insn_8));
+  ASSERT_EQ (LSHIFTRT, GET_CODE (insn_8_src));
+  rtx reg = XEXP (insn_8_src, 0);
+  ASSERT_EQ (REG, GET_CODE (reg));
+  ASSERT_EQ (t.effective_regno (76), REGNO (reg));
+
+  /* Verify that get_insn_by_uid works.  */
+  ASSERT_EQ (insn_8, get_insn_by_uid (8));
+  ASSERT_EQ (insn_9, get_insn_by_uid (9));
+
+  /* Verify that basic blocks were created.  */
+  ASSERT_EQ (2, BLOCK_FOR_INSN (insn_8)->index);
+  ASSERT_EQ (2, BLOCK_FOR_INSN (insn_9)->index);
+
+  /* Verify that a sane CFG was created, with the implicit edges being
+     recreated. */
+  ASSERT_TRUE (cfun);
+  verify_three_block_rtl_cfg (cfun);
+  basic_block bb2 = BASIC_BLOCK_FOR_FN (cfun, 2);
+  ASSERT_TRUE (bb2 != NULL);
+  ASSERT_EQ (BB_RTL, bb2->flags & BB_RTL);
+  ASSERT_EQ (2, bb2->index);
+  ASSERT_EQ (insn_8, BB_HEAD (bb2));
+  ASSERT_EQ (insn_9, BB_END (bb2));
+}
+
+/* Verify loading another RTL dump; this time a dump of copying
+   a param on x86_64 from a hard reg into the frame.  */
+
+static void
+test_loading_dump_fragment_2 ()
+{
+  /* Only run this test for i386, since it hardcodes a hard reg name.  */
+#ifndef I386_OPTS_H
+  return;
+#endif
+
+  rtl_dump_test t (SELFTEST_LOCATION,
+		   locate_file ("copy-hard-reg-into-frame.rtl"));
+
+  rtx_insn *insn = get_insn_by_uid (2);
+
+  /* The block structure and indentation here is purely for
+     readability; it mirrors the structure of the rtx.  */
+  tree mem_expr;
+  {
+    rtx pat = PATTERN (insn);
+    ASSERT_EQ (SET, GET_CODE (pat));
+    {
+      rtx dest = SET_DEST (pat);
+      ASSERT_EQ (MEM, GET_CODE (dest));
+      /* Verify the "/c" was parsed.  */
+      ASSERT_TRUE (RTX_FLAG (dest, call));
+      ASSERT_EQ (SImode, GET_MODE (dest));
+      {
+	rtx addr = XEXP (dest, 0);
+	ASSERT_EQ (PLUS, GET_CODE (addr));
+	ASSERT_EQ (DImode, GET_MODE (addr));
+	{
+	  rtx lhs = XEXP (addr, 0);
+	  ASSERT_EQ (REG, GET_CODE (lhs));
+	  /* Verify the "/f" was parsed.  */
+	  ASSERT_TRUE (RTX_FLAG (lhs, frame_related));
+	  ASSERT_EQ (DImode, GET_MODE (lhs));
+	}
+	{
+	  rtx rhs = XEXP (addr, 1);
+	  ASSERT_EQ (CONST_INT, GET_CODE (rhs));
+	  ASSERT_EQ (-4, INTVAL (rhs));
+	}
+      }
+      /* Verify the "[1 i+0 S4 A32]" was parsed.  */
+      ASSERT_EQ (1, MEM_ALIAS_SET (dest));
+      /* "i" should have been handled by synthesizing a global int
+	 variable named "i".  */
+      mem_expr = MEM_EXPR (dest);
+      ASSERT_NE (mem_expr, NULL);
+      ASSERT_EQ (VAR_DECL, TREE_CODE (mem_expr));
+      ASSERT_EQ (integer_type_node, TREE_TYPE (mem_expr));
+      ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (DECL_NAME (mem_expr)));
+      ASSERT_STREQ ("i", IDENTIFIER_POINTER (DECL_NAME (mem_expr)));
+      /* "+0".  */
+      ASSERT_TRUE (MEM_OFFSET_KNOWN_P (dest));
+      ASSERT_EQ (0, MEM_OFFSET (dest));
+      /* "S4".  */
+      ASSERT_EQ (4, MEM_SIZE (dest));
+      /* "A32.  */
+      ASSERT_EQ (32, MEM_ALIGN (dest));
+    }
+    {
+      rtx src = SET_SRC (pat);
+      ASSERT_EQ (REG, GET_CODE (src));
+      ASSERT_EQ (SImode, GET_MODE (src));
+      ASSERT_EQ (5, REGNO (src));
+      tree reg_expr = REG_EXPR (src);
+      /* "i" here should point to the same var as for the MEM_EXPR.  */
+      ASSERT_EQ (reg_expr, mem_expr);
+    }
+  }
+}
+
+/* Verify that CODE_LABEL insns are loaded correctly.  */
+
+static void
+test_loading_labels ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("example-labels.rtl"));
+
+  rtx_insn *insn_1 = get_insn_by_uid (1);
+  ASSERT_EQ (CODE_LABEL, GET_CODE (insn_1));
+  ASSERT_EQ (NULL, LABEL_NAME (insn_1));
+  ASSERT_EQ (0, LABEL_NUSES (insn_1));
+
+  rtx_insn *insn_2 = get_insn_by_uid (2);
+  ASSERT_EQ (CODE_LABEL, GET_CODE (insn_2));
+  ASSERT_STREQ ("some_label_name", LABEL_NAME (insn_2));
+  ASSERT_EQ (57, LABEL_NUSES (insn_2));
+
+  /* Ensure that label names read from a dump are GC-managed
+     and are found through the insn.  */
+  forcibly_ggc_collect ();
+  ASSERT_TRUE (ggc_marked_p (insn_2));
+  ASSERT_TRUE (ggc_marked_p (LABEL_NAME (insn_2)));
+}
+
+/* Verify that the loader copes with an insn with a mode.  */
+
+static void
+test_loading_insn_with_mode ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("insn-with-mode.rtl"));
+  rtx_insn *insn = get_insn_by_uid (31);
+  ASSERT_EQ (INSN, GET_CODE (insn));
+
+  /* Verify that the "TI" mode was set from "insn:TI".  */
+  ASSERT_EQ (TImode, GET_MODE (insn));
+}
+
+/* Verify that the loader copes with a jump_insn to a label_ref.  */
+
+static void
+test_loading_jump_to_label_ref ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("jump-to-label-ref.rtl"));
+
+  rtx_insn *jump_insn = get_insn_by_uid (1);
+  ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+
+  rtx_insn *barrier = get_insn_by_uid (2);
+  ASSERT_EQ (BARRIER, GET_CODE (barrier));
+
+  rtx_insn *code_label = get_insn_by_uid (3);
+  ASSERT_EQ (CODE_LABEL, GET_CODE (code_label));
+
+  /* Verify the jump_insn. */
+  ASSERT_EQ (4, BLOCK_FOR_INSN (jump_insn)->index);
+  ASSERT_EQ (SET, GET_CODE (PATTERN (jump_insn)));
+  /* Ensure that the "(pc)" is using the global singleton.  */
+  ASSERT_EQ (pc_rtx, SET_DEST (PATTERN (jump_insn)));
+  // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+  rtx label_ref = SET_SRC (PATTERN (jump_insn));
+  ASSERT_EQ (LABEL_REF, GET_CODE (label_ref));
+  ASSERT_EQ (code_label, LABEL_REF_LABEL (label_ref));
+  ASSERT_EQ (code_label, JUMP_LABEL (jump_insn));
+
+  /* Verify the code_label. */
+  ASSERT_EQ (5, BLOCK_FOR_INSN (code_label)->index);
+  ASSERT_EQ (NULL, LABEL_NAME (code_label));
+  ASSERT_EQ (1, LABEL_NUSES (code_label));
+
+  /* Verify the generated CFG.  */
+
+  /* Locate blocks.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (ENTRY_BLOCK, entry->index);
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (cfun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (EXIT_BLOCK, exit->index);
+
+  basic_block bb4 = (*cfun->cfg->x_basic_block_info)[4];
+  basic_block bb5 = (*cfun->cfg->x_basic_block_info)[5];
+  ASSERT_EQ (4, bb4->index);
+  ASSERT_EQ (5, bb5->index);
+
+  /* Entry block.  */
+  ASSERT_EQ (NULL, entry->preds);
+  ASSERT_EQ (1, entry->succs->length ());
+  ASSERT_EDGE ((*entry->succs)[0], 0, 4, EDGE_FALLTHRU);
+
+  /* bb4.  */
+  ASSERT_EQ (1, bb4->preds->length ());
+  ASSERT_EDGE ((*bb4->preds)[0], 0, 4, EDGE_FALLTHRU);
+  ASSERT_EQ (1, bb4->succs->length ());
+  ASSERT_EDGE ((*bb4->succs)[0], 4, 5, 0x0);
+
+  /* bb5.  */
+  ASSERT_EQ (1, bb5->preds->length ());
+  ASSERT_EDGE ((*bb5->preds)[0], 4, 5, 0x0);
+  ASSERT_EQ (1, bb5->succs->length ());
+  ASSERT_EDGE ((*bb5->succs)[0], 5, 1, EDGE_FALLTHRU);
+
+  /* Exit block.  */
+  ASSERT_EQ (1, exit->preds->length ());
+  ASSERT_EDGE ((*exit->preds)[0], 5, 1, EDGE_FALLTHRU);
+  ASSERT_EQ (NULL, exit->succs);
+}
+
+/* Verify that the loader copes with a jump_insn to a label_ref
+   marked "return".  */
+
+static void
+test_loading_jump_to_return ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("jump-to-return.rtl"));
+
+  rtx_insn *jump_insn = get_insn_by_uid (1);
+  ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+  ASSERT_EQ (ret_rtx, JUMP_LABEL (jump_insn));
+  // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+}
+
+/* Verify that the loader copes with a jump_insn to a label_ref
+   marked "simple_return".  */
+
+static void
+test_loading_jump_to_simple_return ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION,
+		   locate_file ("jump-to-simple-return.rtl"));
+
+  rtx_insn *jump_insn = get_insn_by_uid (1);
+  ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+  ASSERT_EQ (simple_return_rtx, JUMP_LABEL (jump_insn));
+  // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+}
+
+/* Verify that the loader copes with a NOTE_INSN_BASIC_BLOCK.  */
+
+static void
+test_loading_note_insn_basic_block ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION,
+		   locate_file ("note_insn_basic_block.rtl"));
+
+  rtx_insn *note = get_insn_by_uid (1);
+  ASSERT_EQ (NOTE, GET_CODE (note));
+  ASSERT_EQ (2, BLOCK_FOR_INSN (note)->index);
+
+  ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (note));
+  ASSERT_EQ (2, NOTE_BASIC_BLOCK (note)->index);
+  ASSERT_EQ (BASIC_BLOCK_FOR_FN (cfun, 2), NOTE_BASIC_BLOCK (note));
+}
+
+/* Verify that the loader copes with a NOTE_INSN_DELETED.  */
+
+static void
+test_loading_note_insn_deleted ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("note-insn-deleted.rtl"));
+
+  rtx_insn *note = get_insn_by_uid (1);
+  ASSERT_EQ (NOTE, GET_CODE (note));
+  ASSERT_EQ (NOTE_INSN_DELETED, NOTE_KIND (note));
+}
+
+/* Verify that the const_int values are consolidated, since
+   pointer equality corresponds to value equality.
+   TODO: do this for all in CASE_CONST_UNIQUE.  */
+
+static void
+test_loading_const_int ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("const-int.rtl"));
+
+  /* Verify that const_int values below MAX_SAVED_CONST_INT use
+     the global values.  */
+  ASSERT_EQ (const0_rtx, SET_SRC (PATTERN (get_insn_by_uid (100))));
+  ASSERT_EQ (const1_rtx, SET_SRC (PATTERN (get_insn_by_uid (101))));
+  ASSERT_EQ (constm1_rtx, SET_SRC (PATTERN (get_insn_by_uid (102))));
+
+  /* Verify that other const_int values are consolidated. */
+  rtx int256 = gen_rtx_CONST_INT (SImode, 256);
+  ASSERT_EQ (int256, SET_SRC (PATTERN (get_insn_by_uid (103))));
+}
+
+/* Verify that the loader copes with a SYMBOL_REF.  */
+
+static void
+test_loading_symbol_ref ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("symbol-ref.rtl"));
+
+  rtx_insn *insn = get_insn_by_uid (1045);
+
+  rtx high = SET_SRC (PATTERN (insn));
+  ASSERT_EQ (HIGH, GET_CODE (high));
+
+  rtx symbol_ref = XEXP (high, 0);
+  ASSERT_EQ (SYMBOL_REF, GET_CODE (symbol_ref));
+
+  /* Verify that "[flags 0xc0]" was parsed.  */
+  ASSERT_EQ (0xc0, SYMBOL_REF_FLAGS (symbol_ref));
+  /* TODO: we don't yet load SYMBOL_REF_DECL.  */
+}
+
+/* Verify that the loader copes with a call_insn dump.  */
+
+static void
+test_loading_call_insn_x86_64 ()
+{
+  /* Only run this test for i386.  */
+#ifndef I386_OPTS_H
+  return;
+#endif
+
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/call-insn.rtl"));
+
+  rtx_insn *insn_17 = get_insn_by_uid (17);
+  ASSERT_EQ (CALL_INSN, GET_CODE (insn_17));
+
+  /* "/j".  */
+  ASSERT_TRUE (RTX_FLAG (insn_17, jump));
+
+  rtx pat = PATTERN (insn_17);
+  ASSERT_EQ (CALL, GET_CODE (SET_SRC (pat)));
+
+  /* Verify REG_NOTES.  */
+  {
+    /* "(expr_list:REG_CALL_DECL".   */
+    ASSERT_EQ (EXPR_LIST, GET_CODE (REG_NOTES (insn_17)));
+    rtx_expr_list *note0 = as_a <rtx_expr_list *> (REG_NOTES (insn_17));
+    ASSERT_EQ (REG_CALL_DECL, REG_NOTE_KIND (note0));
+
+    /* "(expr_list:REG_EH_REGION (const_int 0 [0])".  */
+    rtx_expr_list *note1 = note0->next ();
+    ASSERT_EQ (REG_EH_REGION, REG_NOTE_KIND (note1));
+
+    ASSERT_EQ (NULL, note1->next ());
+  }
+
+  /* Verify CALL_INSN_FUNCTION_USAGE.  */
+  {
+    /* "(expr_list:DF (use (reg:DF 21 xmm0))".  */
+    rtx_expr_list *usage
+      = as_a <rtx_expr_list *> (CALL_INSN_FUNCTION_USAGE (insn_17));
+    ASSERT_EQ (EXPR_LIST, GET_CODE (usage));
+    ASSERT_EQ (DFmode, GET_MODE (usage));
+    ASSERT_EQ (USE, GET_CODE (usage->element ()));
+    ASSERT_EQ (NULL, usage->next ());
+  }
+}
+
+/* Verify that the loader copes a dump from print_rtx_function.  */
+
+static void
+test_loading_full_dump_aarch64 ()
+{
+  /* Only run this test for target==aarch64.  */
+#ifndef GCC_AARCH64_H
+  return;
+#endif
+
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("aarch64/times-two.rtl"));
+
+  ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+  rtx_insn *insn_1 = get_insn_by_uid (1);
+  ASSERT_EQ (NOTE, GET_CODE (insn_1));
+
+  rtx_insn *insn_15 = get_insn_by_uid (15);
+  ASSERT_EQ (INSN, GET_CODE (insn_15));
+  ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
+
+  /* Verify crtl->return_rtx.  */
+  ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
+  ASSERT_EQ (0, REGNO (crtl->return_rtx));
+  ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
+}
+
+/* Verify that the loader copes a dump from print_rtx_function.  */
+
+static void
+test_loading_full_dump_x86_64 ()
+{
+  /* Only run this test for i386.  */
+#ifndef I386_OPTS_H
+  return;
+#endif
+
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/times-two.rtl"));
+
+  ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+  rtx_insn *insn_1 = get_insn_by_uid (1);
+  ASSERT_EQ (NOTE, GET_CODE (insn_1));
+
+  rtx_insn *insn_7 = get_insn_by_uid (7);
+  ASSERT_EQ (INSN, GET_CODE (insn_7));
+  ASSERT_EQ (PARALLEL, GET_CODE (PATTERN (insn_7)));
+
+  rtx_insn *insn_15 = get_insn_by_uid (15);
+  ASSERT_EQ (INSN, GET_CODE (insn_15));
+  ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
+
+  /* Verify crtl->return_rtx.  */
+  ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
+  ASSERT_EQ (0, REGNO (crtl->return_rtx));
+  ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
+}
+
+/* Verify that the loader can rebuild a CFG.  */
+
+static void
+test_loading_cfg ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("cfg-test.rtl"));
+
+  ASSERT_STREQ ("cfg_test", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+  ASSERT_TRUE (cfun);
+
+  ASSERT_TRUE (cfun->cfg != NULL);
+  ASSERT_EQ (6, n_basic_blocks_for_fn (cfun));
+  ASSERT_EQ (6, n_edges_for_fn (cfun));
+
+  /* The "fake" basic blocks.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+  ASSERT_TRUE (entry != NULL);
+  ASSERT_EQ (ENTRY_BLOCK, entry->index);
+
+  basic_block exit = EXIT_BLOCK_PTR_FOR_FN (cfun);
+  ASSERT_TRUE (exit != NULL);
+  ASSERT_EQ (EXIT_BLOCK, exit->index);
+
+  /* The "real" basic blocks.  */
+  basic_block bb2 = (*cfun->cfg->x_basic_block_info)[2];
+  basic_block bb3 = (*cfun->cfg->x_basic_block_info)[3];
+  basic_block bb4 = (*cfun->cfg->x_basic_block_info)[4];
+  basic_block bb5 = (*cfun->cfg->x_basic_block_info)[5];
+
+  ASSERT_EQ (2, bb2->index);
+  ASSERT_EQ (3, bb3->index);
+  ASSERT_EQ (4, bb4->index);
+  ASSERT_EQ (5, bb5->index);
+
+  /* Verify connectivity.  */
+
+  /* Entry block.  */
+  ASSERT_EQ (NULL, entry->preds);
+  ASSERT_EQ (1, entry->succs->length ());
+  ASSERT_EDGE ((*entry->succs)[0], 0, 2, 0x1);
+
+  /* bb2.  */
+  ASSERT_EQ (1, bb2->preds->length ());
+  ASSERT_EDGE ((*bb2->preds)[0], 0, 2, 0x1);
+  ASSERT_EQ (2, bb2->succs->length ());
+  ASSERT_EDGE ((*bb2->succs)[0], 2, 3, 0x1);
+  ASSERT_EDGE ((*bb2->succs)[1], 2, 4, 0x1);
+
+  /* bb3.  */
+  ASSERT_EQ (1, bb3->preds->length ());
+  ASSERT_EDGE ((*bb3->preds)[0], 2, 3, 0x1);
+  ASSERT_EQ (1, bb3->succs->length ());
+  ASSERT_EDGE ((*bb3->succs)[0], 3, 5, 0x1);
+
+  /* bb4.  */
+  ASSERT_EQ (1, bb4->preds->length ());
+  ASSERT_EDGE ((*bb4->preds)[0], 2, 4, 0x1);
+  ASSERT_EQ (1, bb4->succs->length ());
+  ASSERT_EDGE ((*bb4->succs)[0], 4, 5, 0x1);
+
+  /* bb5.  */
+  ASSERT_EQ (2, bb5->preds->length ());
+  ASSERT_EDGE ((*bb5->preds)[0], 3, 5, 0x1);
+  ASSERT_EDGE ((*bb5->preds)[1], 4, 5, 0x1);
+  ASSERT_EQ (1, bb5->succs->length ());
+  ASSERT_EDGE ((*bb5->succs)[0], 5, 1, 0x1);
+
+  /* Exit block.  */
+  ASSERT_EQ (1, exit->preds->length ());
+  ASSERT_EDGE ((*exit->preds)[0], 5, 1, 0x1);
+  ASSERT_EQ (NULL, exit->succs);
+}
+
+/* Verify that renumbering pseudos works.  */
+
+static void
+test_regno_renumbering ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION,
+		   locate_file ("test-regno-renumbering.rtl"));
+
+  rtx_insn *insn_1 = get_insn_by_uid (1);
+  rtx set = single_set (insn_1);
+  ASSERT_NE (NULL, set);
+  rtx dst = SET_DEST (set);
+  rtx src = SET_SRC (set);
+  /* The registers did not have names, and so should have been treated
+     as pseudos.
+     Verify that they have been renumbered, with the lower one
+     having LAST_VIRTUAL_REGISTER + 1.  */
+  ASSERT_EQ (LAST_VIRTUAL_REGISTER + 1, REGNO (dst));
+  ASSERT_EQ (LAST_VIRTUAL_REGISTER + 2, REGNO (src));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+read_rtl_function_c_tests ()
+{
+  test_loading_dump_fragment_1 ();
+  test_loading_dump_fragment_2 ();
+  test_loading_labels ();
+  test_loading_insn_with_mode ();
+  test_loading_jump_to_label_ref ();
+  test_loading_jump_to_return ();
+  test_loading_jump_to_simple_return ();
+  test_loading_note_insn_basic_block ();
+  test_loading_note_insn_deleted ();
+  test_loading_const_int ();
+  test_loading_symbol_ref ();
+  test_loading_call_insn_x86_64 ();
+  test_loading_full_dump_aarch64 ();
+  test_loading_full_dump_x86_64 ();
+  test_loading_cfg ();
+  test_regno_renumbering ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
new file mode 100644
index 0000000..d26c797
--- /dev/null
+++ b/gcc/read-rtl-function.h
@@ -0,0 +1,37 @@
+/* read-rtl-function.h - Reader for RTL function dumps
+   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/>.  */
+
+#ifndef GCC_READ_RTL_FUNCTION_H
+#define GCC_READ_RTL_FUNCTION_H
+
+/* An optional policy class for class function_reader.  */
+
+struct function_reader_policy
+{
+  function_reader_policy ()
+  {
+  }
+};
+
+extern bool read_rtl_function_body (int argc, const char **argv,
+				    bool (*parse_opt) (const char *),
+				    function_reader_policy *policy,
+				    int *out_pseudo_offset);
+
+#endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 2622bfe..5e8f0fb 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -17,7 +17,13 @@ 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/>.  */
 
+/* This file is compiled twice: once for the generator programs
+   once for the compiler.  */
+#ifdef GENERATOR_FILE
 #include "bconfig.h"
+#else
+#include "config.h"
+#endif
 
 /* Disable rtl checking; it conflicts with the iterator handling.  */
 #undef ENABLE_RTL_CHECKING
@@ -30,6 +36,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "read-md.h"
 #include "gensupport.h"
 
+#ifndef GENERATOR_FILE
+#include "function.h"
+#include "emit-rtl.h"
+#endif
+
 /* One element in a singly-linked list of (integer, string) pairs.  */
 struct map_value {
   struct map_value *next;
@@ -106,6 +117,7 @@ htab_t subst_attr_to_iter_map = NULL;
 const char *current_iterator_name;
 
 static void validate_const_int (const char *);
+static void one_time_initialization (void);
 
 /* Global singleton.  */
 rtx_reader *rtx_reader_ptr = NULL;
@@ -181,6 +193,8 @@ apply_int_iterator (void *loc, int value)
   *(int *)loc = value;
 }
 
+#ifdef GENERATOR_FILE
+
 /* This routine adds attribute or does nothing depending on VALUE.  When
    VALUE is 1, it does nothing - the first duplicate of original
    template is kept untouched when it's subjected to a define_subst.
@@ -252,6 +266,8 @@ bind_subst_iter_and_attr (const char *iter, const char *attr)
   *slot = value;
 }
 
+#endif /* #ifdef GENERATOR_FILE */
+
 /* Return name of a subst-iterator, corresponding to subst-attribute ATTR.  */
 
 static char*
@@ -418,6 +434,8 @@ copy_rtx_for_iterators (rtx original)
   return x;
 }
 
+#ifdef GENERATOR_FILE
+
 /* Return a condition that must satisfy both ORIGINAL and EXTRA.  If ORIGINAL
    has the form "&& ..." (as used in define_insn_and_splits), assume that
    EXTRA is already satisfied.  Empty strings are treated like "true".  */
@@ -581,6 +599,7 @@ apply_iterators (rtx original, vec<rtx> *queue)
 	}
     }
 }
+#endif /* #ifdef GENERATOR_FILE */
 
 /* Add a new "mapping" structure to hashtable TABLE.  NAME is the name
    of the mapping and GROUP is the group to which it belongs.  */
@@ -655,7 +674,9 @@ initialize_iterators (void)
   substs.iterators = htab_create (13, leading_string_hash,
 				 leading_string_eq_p, 0);
   substs.find_builtin = find_int; /* We don't use it, anyway.  */
+#ifdef GENERATOR_FILE
   substs.apply_iterator = apply_subst_iterator;
+#endif
 
   lower = add_mapping (&modes, modes.attrs, "mode");
   upper = add_mapping (&modes, modes.attrs, "MODE");
@@ -724,6 +745,8 @@ atoll (const char *p)
 }
 #endif
 \f
+
+#ifdef GENERATOR_FILE
 /* Process a define_conditions directive, starting with the optional
    space after the "define_conditions".  The directive looks like this:
 
@@ -765,6 +788,7 @@ read_conditions (void)
       add_c_test (expr, value);
     }
 }
+#endif /* #ifdef GENERATOR_FILE */
 
 static void
 validate_const_int (const char *string)
@@ -861,6 +885,8 @@ record_potential_iterator_use (struct iterator_group *group, void *ptr,
     }
 }
 
+#ifdef GENERATOR_FILE
+
 /* Finish reading a declaration of the form:
 
        (define... <name> [<value1> ... <valuen>])
@@ -1020,14 +1046,7 @@ check_code_iterator (struct mapping *iterator)
 bool
 read_rtx (const char *rtx_name, vec<rtx> *rtxen)
 {
-  static bool initialized = false;
-
-  /* Do one-time initialization.  */
-  if (!initialized)
-    {
-      initialize_iterators ();
-      initialized = true;
-    }
+  one_time_initialization ();
 
   /* Handle various rtx-related declarations that aren't themselves
      encoded as rtxes.  */
@@ -1082,6 +1101,103 @@ read_rtx (const char *rtx_name, vec<rtx> *rtxen)
   return true;
 }
 
+#endif /* #ifdef GENERATOR_FILE */
+
+/* Do one-time initialization.  */
+
+static void
+one_time_initialization (void)
+{
+  static bool initialized = false;
+
+  if (!initialized)
+    {
+      initialize_iterators ();
+      initialized = true;
+    }
+}
+
+/* Consume characters until encountering a character in TERMINATOR_CHARS,
+   consuming the terminator character if CONSUME_TERMINATOR is true.
+   Return all characters before the terminator as an allocated buffer.  */
+
+char *
+rtx_reader::read_until (const char *terminator_chars, bool consume_terminator)
+{
+  int ch = read_skip_spaces ();
+  unread_char (ch);
+  auto_vec<char> buf;
+  while (1)
+    {
+      ch = read_char ();
+      if (strchr (terminator_chars, ch))
+	{
+	  if (!consume_terminator)
+	    unread_char (ch);
+	  break;
+	}
+      buf.safe_push (ch);
+    }
+  buf.safe_push ('\0');
+  return xstrdup (buf.address ());
+}
+
+/* Subroutine of read_rtx_code, for parsing zero or more flags.  */
+
+static void
+read_flags (rtx return_rtx)
+{
+  while (1)
+    {
+      int ch = read_char ();
+      if (ch != '/')
+	{
+	  unread_char (ch);
+	  break;
+	}
+
+      int flag_char = read_char ();
+      switch (flag_char)
+	{
+	  case 's':
+	    RTX_FLAG (return_rtx, in_struct) = 1;
+	    break;
+	  case 'v':
+	    RTX_FLAG (return_rtx, volatil) = 1;
+	    break;
+	  case 'u':
+	    RTX_FLAG (return_rtx, unchanging) = 1;
+	    break;
+	  case 'f':
+	    RTX_FLAG (return_rtx, frame_related) = 1;
+	    break;
+	  case 'j':
+	    RTX_FLAG (return_rtx, jump) = 1;
+	    break;
+	  case 'c':
+	    RTX_FLAG (return_rtx, call) = 1;
+	    break;
+	  case 'i':
+	    RTX_FLAG (return_rtx, return_val) = 1;
+	    break;
+	  default:
+	    fatal_with_file_and_line ("unrecognized flag: `%c'", flag_char);
+	}
+    }
+}
+
+/* Return the numeric value n for GET_REG_NOTE_NAME (n) for STRING,
+   or fail if STRING isn't recognized.  */
+
+static int
+parse_reg_note_name (const char *string)
+{
+  for (int i = 0; i < REG_NOTE_MAX; i++)
+    if (0 == strcmp (string, GET_REG_NOTE_NAME (i)))
+      return i;
+  fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
+}
+
 /* Subroutine of read_rtx and read_nested_rtx.  CODE_NAME is the name of
    either an rtx code or a code iterator.  Parse the rest of the rtx and
    return it.  */
@@ -1090,7 +1206,7 @@ rtx
 rtx_reader::read_rtx_code (const char *code_name)
 {
   RTX_CODE code;
-  struct mapping *iterator;
+  struct mapping *iterator = NULL;
   const char *format_ptr;
   struct md_name name;
   rtx return_rtx;
@@ -1103,13 +1219,19 @@ rtx_reader::read_rtx_code (const char *code_name)
       rtx value;		/* Value of this node.  */
     };
 
+  one_time_initialization ();
+
   /* If this code is an iterator, build the rtx using the iterator's
      first value.  */
+#ifdef GENERATOR_FILE
   iterator = (struct mapping *) htab_find (codes.iterators, &code_name);
   if (iterator != 0)
     code = (enum rtx_code) iterator->values->number;
   else
     code = (enum rtx_code) codes.find_builtin (code_name);
+#else
+    code = (enum rtx_code) codes.find_builtin (code_name);
+#endif
 
   /* If we end up with an insn expression then we free this space below.  */
   return_rtx = rtx_alloc (code);
@@ -1120,6 +1242,26 @@ rtx_reader::read_rtx_code (const char *code_name)
   if (iterator)
     record_iterator_use (iterator, return_rtx);
 
+  /* Check for flags. */
+  read_flags (return_rtx);
+
+  /* Read REG_NOTE names for EXPR_LIST and INSN_LIST.  */
+  if ((GET_CODE (return_rtx) == EXPR_LIST
+       || GET_CODE (return_rtx) == INSN_LIST
+       || GET_CODE (return_rtx) == INT_LIST)
+      && !m_in_call_function_usage)
+    {
+      char ch = read_char ();
+      if (ch == ':')
+	{
+	  read_name (&name);
+	  PUT_MODE_RAW (return_rtx,
+			(machine_mode)parse_reg_note_name (name.string));
+	}
+      else
+	unread_char (ch);
+    }
+
   /* If what follows is `: mode ', read it and
      store the mode in the rtx.  */
 
@@ -1132,8 +1274,24 @@ rtx_reader::read_rtx_code (const char *code_name)
   else
     unread_char (c);
 
+  if (INSN_CHAIN_CODE_P (code))
+    {
+      read_name (&name);
+      INSN_UID (return_rtx) = atoi (name.string);
+    }
+
+  /* Use the format_ptr to parse the various operands of this rtx.
+     read_rtx_operand is a vfunc, allowing the parser to vary between
+     parsing .md files and parsing .rtl dumps; the function_reader subclass
+     overrides the defaults when loading RTL dumps, to handle the
+     various extra attributes emitted by print_rtx.  */
   for (int idx = 0; format_ptr[idx] != 0; idx++)
-    read_rtx_operand (return_rtx, idx);
+    return_rtx = read_rtx_operand (return_rtx, idx);
+
+  /* Call a vfunc to handle the various additional information that
+     print-rtl.c can write after the regular fields; does nothing when
+     parsing .md files.  */
+  handle_any_trailing_information (return_rtx);
 
   if (CONST_WIDE_INT_P (return_rtx))
     {
@@ -1217,6 +1375,9 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
       break;
 
     case 'e':
+      XEXP (return_rtx, idx) = read_nested_rtx ();
+      break;
+
     case 'u':
       XEXP (return_rtx, idx) = read_nested_rtx ();
       break;
@@ -1292,7 +1453,10 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
 	star_if_braced = (format_ptr[idx] == 'T');
 
 	stringbuf = read_string (star_if_braced);
+	if (!stringbuf)
+	  break;
 
+#ifdef GENERATOR_FILE
 	/* For insn patterns, we want to provide a default name
 	   based on the file and line, like "*foo.md:12", if the
 	   given name is blank.  These are only for define_insn and
@@ -1347,11 +1511,23 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
 	    if (m != 0)
 	      record_iterator_use (m, return_rtx);
 	  }
+#endif /* #ifdef GENERATOR_FILE */
+
+	/* "stringbuf" was allocated within string_obstack and thus has
+	   the its lifetime restricted to that of the rtx_reader.  This is
+	   OK for the generator programs, but for non-generator programs,
+	   XSTR and XTMPL fields are meant to be allocated in the GC-managed
+	   heap.  Hence we need to allocate a copy in the GC-managed heap
+	   for the non-generator case.  */
+	const char *string_ptr = stringbuf;
+#ifndef GENERATOR_FILE
+	string_ptr = ggc_strdup (stringbuf);
+#endif /* #ifndef GENERATOR_FILE */
 
 	if (star_if_braced)
-	  XTMPL (return_rtx, idx) = stringbuf;
+	  XTMPL (return_rtx, idx) = string_ptr;
 	else
-	  XSTR (return_rtx, idx) = stringbuf;
+	  XSTR (return_rtx, idx) = string_ptr;
       }
       break;
 
@@ -1419,6 +1595,8 @@ rtx_reader::read_nested_rtx (void)
 
   require_char_ws (')');
 
+  return_rtx = postprocess (return_rtx);
+
   return return_rtx;
 }
 
@@ -1456,7 +1634,8 @@ rtx_reader::read_rtx_variadic (rtx form)
 /* Constructor for class rtx_reader.  */
 
 rtx_reader::rtx_reader ()
-: base_rtx_reader ()
+: base_rtx_reader (),
+  m_in_call_function_usage (false)
 {
   /* Set the global singleton pointer.  */
   rtx_reader_ptr = this;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index ce1131b..0741fc6 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3641,7 +3641,9 @@ extern void init_varasm_once (void);
 extern rtx make_debug_expr_from_rtl (const_rtx);
 
 /* In read-rtl.c */
+#ifdef GENERATOR_FILE
 extern bool read_rtx (const char *, vec<rtx> *);
+#endif
 
 /* In alias.c */
 extern rtx canon_rtx (rtx);
diff --git a/gcc/selftest-rtl.c b/gcc/selftest-rtl.c
new file mode 100644
index 0000000..0849cc6
--- /dev/null
+++ b/gcc/selftest-rtl.c
@@ -0,0 +1,90 @@
+/* Selftest support for RTL.
+   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 "selftest.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "read-rtl-function.h"
+#include "read-md.h"
+#include "tree-core.h"
+#include "emit-rtl.h"
+#include "selftest-rtl.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Constructor for selftest::rtl_dump_test.
+   Read a dumped RTL function from PATH.
+   Takes ownership of PATH, freeing in dtor.
+   Use LOC as the effective location when reporting failures.  */
+
+rtl_dump_test::rtl_dump_test (const location &loc, char *path)
+  : m_path (path), m_pseudo_offset (0)
+{
+  /* Parse the tempfile.  */
+  auto_vec<const char *> argv (2);
+  argv.safe_push (progname);
+  argv.safe_push (path);
+  bool read_ok
+    = read_rtl_function_body (argv.length (), argv.address (), NULL, NULL,
+			      &m_pseudo_offset);
+  ASSERT_TRUE_AT (loc, read_ok);
+}
+
+/* Destructor for selftest::rtl_dump_test.
+   Cleanup global state relating to the function, and free the path.  */
+
+selftest::rtl_dump_test::~rtl_dump_test ()
+{
+  /* Cleanups.  */
+  current_function_decl = NULL;
+  free_after_compilation (cfun);
+  set_cfun (NULL);
+  free (m_path);
+}
+
+/* Given INPUT_REGNO, a register number in the input RTL dump, return
+   the effective register number that was used.  */
+unsigned int
+selftest::rtl_dump_test::effective_regno (int input_regno) const
+{
+  return input_regno + m_pseudo_offset;
+}
+
+/* Get the insn with the given uid, or NULL if not found.  */
+
+rtx_insn *
+get_insn_by_uid (int uid)
+{
+  for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (INSN_UID (insn) == uid)
+      return insn;
+
+  /* Not found.  */
+  return NULL;
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-rtl.h b/gcc/selftest-rtl.h
new file mode 100644
index 0000000..4858f3a
--- /dev/null
+++ b/gcc/selftest-rtl.h
@@ -0,0 +1,67 @@
+/* A self-testing framework, for use by -fself-test.
+   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/>.  */
+
+#ifndef GCC_SELFTEST_RTL_H
+#define GCC_SELFTEST_RTL_H
+
+/* The selftest code should entirely disappear in a production
+   configuration, hence we guard all of it with #if CHECKING_P.  */
+
+#if CHECKING_P
+
+#include "read-rtl-function.h"
+
+namespace selftest {
+
+/* A class for testing RTL function dumps.  */
+
+class rtl_dump_test
+{
+ public:
+  /* Takes ownership of PATH.  */
+  rtl_dump_test (const location &loc, char *path);
+  ~rtl_dump_test ();
+
+  unsigned int effective_regno (int input_regno) const;
+
+ private:
+  char *m_path;
+  int m_pseudo_offset;
+};
+
+/* Wrapper class for initializing/cleaning up df.  */
+
+class dataflow_test
+{
+ public:
+  dataflow_test ();
+  ~dataflow_test ();
+};
+
+/* Get the insn with the given uid, or NULL if not found.  */
+
+extern rtx_insn *get_insn_by_uid (int uid);
+
+extern void verify_three_block_rtl_cfg (function *fun);
+
+} /* end of namespace selftest.  */
+
+#endif /* #if CHECKING_P */
+
+#endif /* GCC_SELFTEST_RTL_H */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index ecc3d71..1dce665 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -70,6 +70,7 @@ selftest::run_tests ()
   tree_c_tests ();
   gimple_c_tests ();
   rtl_tests_c_tests ();
+  read_rtl_function_c_tests ();
 
   /* Higher-level tests, or for components that other selftests don't
      rely on.  */
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 8b9c007..ae39101 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -213,6 +213,7 @@ extern void hash_map_tests_c_tests ();
 extern void hash_set_tests_c_tests ();
 extern void input_c_tests ();
 extern void pretty_print_c_tests ();
+extern void read_rtl_function_c_tests ();
 extern void rtl_tests_c_tests ();
 extern void selftest_c_tests ();
 extern void spellcheck_c_tests ();
diff --git a/gcc/testsuite/selftests/aarch64/times-two.rtl b/gcc/testsuite/selftests/aarch64/times-two.rtl
new file mode 100644
index 0000000..8d198f2
--- /dev/null
+++ b/gcc/testsuite/selftests/aarch64/times-two.rtl
@@ -0,0 +1,42 @@
+(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 68 virtual-stack-vars)
+                        (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+                (reg:SI 0 x0 [ i ])) times-two.c:2 -1
+             (nil))
+    (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
+    (insn 6 3 7 2 (set (reg:SI 75)
+                (mem/c:SI (plus:DI (reg/f:DI 68 virtual-stack-vars)
+                        (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) times-two.c:3 -1
+             (nil))
+    (insn 7 6 10 2 (set (reg:SI 73 [ _2 ])
+                (ashift:SI (reg:SI 75)
+                    (const_int 1 [0x1]))) times-two.c:3 -1
+             (nil))
+    (insn 10 7 14 2 (set (reg:SI 74 [ <retval> ])
+                (reg:SI 73 [ _2 ])) times-two.c:3 -1
+             (nil))
+    (insn 14 10 15 2 (set (reg/i:SI 0 x0)
+                (reg:SI 74 [ <retval> ])) times-two.c:4 -1
+             (nil))
+    (insn 15 14 0 2 (use (reg/i:SI 0 x0)) times-two.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 x0)
+    ) ;; return_rtx
+  ) ;; crtl
+) ;; function "times_two"
diff --git a/gcc/testsuite/selftests/asr_div1.rtl b/gcc/testsuite/selftests/asr_div1.rtl
new file mode 100644
index 0000000..2c2a825
--- /dev/null
+++ b/gcc/testsuite/selftests/asr_div1.rtl
@@ -0,0 +1,23 @@
+;; Taken from
+;;    gcc/testsuite/gcc.dg/asr_div1.c -O2 -fdump-rtl-all -mtune=cortex-a53
+;; for aarch64, hand editing the prev/next insns to 0 as needed, and
+;; editing whitespace to avoid over-long lines.  */
+
+(function "f1"
+  (insn-chain
+(insn 8 0 9 2 (set (reg:DI 78)
+        (lshiftrt:DI (reg:DI 76)
+            (const_int 32 [0x20])))
+        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14
+        641 {*aarch64_lshr_sisd_or_int_di3}
+     (expr_list:REG_DEAD (reg:DI 76)
+        (nil)))
+(insn 9 8 0 2 (set (reg:SI 79)
+        (ashiftrt:SI (subreg:SI (reg:DI 78) 0)
+            (const_int 3 [0x3])))
+        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14
+        642 {*aarch64_ashr_sisd_or_int_si3}
+     (expr_list:REG_DEAD (reg:DI 78)
+        (nil)))
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/cfg-test.rtl b/gcc/testsuite/selftests/cfg-test.rtl
new file mode 100644
index 0000000..d6be7f9
--- /dev/null
+++ b/gcc/testsuite/selftests/cfg-test.rtl
@@ -0,0 +1,38 @@
+/* Example of a loading a CFG like this:
+       0  (entry)
+       |
+       2
+      / \
+     3   4
+      \ /
+       5
+       |
+       1  (exit).  */
+
+(function "cfg_test"
+  (insn-chain
+     (note 2 0 3 2 [bb 2] NOTE_INSN_BASIC_BLOCK)  
+     (note 3 2 4 3 [bb 3] NOTE_INSN_BASIC_BLOCK)  
+     (note 4 3 5 4 [bb 4] NOTE_INSN_BASIC_BLOCK)  
+     (note 5 4 0 5 [bb 5] NOTE_INSN_BASIC_BLOCK)  
+  ) ;; empty
+  (cfg
+     (bb 0 ;; entry
+       (edge 0 2 (flags 0x1))
+     ) ;; bb
+     (bb 2
+       (edge 2 3 (flags 0x1))
+       (edge 2 4 (flags 0x1))
+     ) ;; bb
+     (bb 3
+       (edge 3 5 (flags 0x1))
+     ) ;; bb
+     (bb 4
+       (edge 4 5 (flags 0x1))
+     ) ;; bb
+     (bb 5
+       (edge 5 1 (flags 0x1))
+     ) ;; bb
+     (bb 1) ;; exit
+  ) ;; cfg
+)
diff --git a/gcc/testsuite/selftests/const-int.rtl b/gcc/testsuite/selftests/const-int.rtl
new file mode 100644
index 0000000..933a0bf
--- /dev/null
+++ b/gcc/testsuite/selftests/const-int.rtl
@@ -0,0 +1,16 @@
+(function "const_int_examples"
+  (insn-chain
+    (insn 100 0 101 2
+      (set (reg:SI 100) (const_int 0 [0x0]))
+        test.c:2 -1 (nil))
+    (insn 101 100 102 2
+      (set (reg:SI 101) (const_int 1 [0x1]))
+        test.c:2 -1 (nil))
+    (insn 102 101 103 2
+      (set (reg:SI 102) (const_int -1 [0xffffffff]))
+        test.c:2 -1 (nil))
+    (insn 103 102 0 2
+      (set (reg:SI 103) (const_int 256 [0x100]))
+        test.c:2 -1 (nil))
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/copy-hard-reg-into-frame.rtl b/gcc/testsuite/selftests/copy-hard-reg-into-frame.rtl
new file mode 100644
index 0000000..a8abee4
--- /dev/null
+++ b/gcc/testsuite/selftests/copy-hard-reg-into-frame.rtl
@@ -0,0 +1,12 @@
+(function "copy_hard_reg_into_frame"
+  (insn-chain
+    (insn 2 0 0 2
+      (set (mem/c:SI
+          (plus:DI
+            (reg/f:DI 20 frame)
+            (const_int -4 [0xfffffffffffffffc]))
+          [1 i+0 S4 A32])
+       (reg:SI 5 di [ i ])) test.c:2 -1
+     (nil))
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/example-labels.rtl b/gcc/testsuite/selftests/example-labels.rtl
new file mode 100644
index 0000000..edadcc9
--- /dev/null
+++ b/gcc/testsuite/selftests/example-labels.rtl
@@ -0,0 +1,6 @@
+(function "example_labels"
+  (insn-chain
+    (code_label 1 0 2 6 3 (nil) [0 uses])
+    (code_label 2 1 0 6 3 ("some_label_name") [57 uses])
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/insn-with-mode.rtl b/gcc/testsuite/selftests/insn-with-mode.rtl
new file mode 100644
index 0000000..890e5f9
--- /dev/null
+++ b/gcc/testsuite/selftests/insn-with-mode.rtl
@@ -0,0 +1,5 @@
+(function "insn_with_mode"
+  (insn-chain
+    (insn:TI 31 0 0 2 (set (reg:SI 100) (reg:SI 101)) -1 (nil))
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/jump-to-label-ref.rtl b/gcc/testsuite/selftests/jump-to-label-ref.rtl
new file mode 100644
index 0000000..1089997
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-label-ref.rtl
@@ -0,0 +1,11 @@
+(function "jump_to_label_ref"
+  (insn-chain
+    (jump_insn 1 0 2 4 (set (pc)
+        (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+       -> 3)
+    (barrier 2 1 3)
+    (code_label 3 2 0 5 2 (nil) [1 uses])
+  ) ;; insn-chain
+) ;; function
+
diff --git a/gcc/testsuite/selftests/jump-to-return.rtl b/gcc/testsuite/selftests/jump-to-return.rtl
new file mode 100644
index 0000000..1316d03
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-return.rtl
@@ -0,0 +1,10 @@
+(function "jump_to_return"
+  (insn-chain
+    (jump_insn 1 0 2 4 (set (pc)
+        (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+      -> return)
+    (barrier 2 1 3)
+    (code_label 3 2 0 5 2 (nil) [1 uses])
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/jump-to-simple-return.rtl b/gcc/testsuite/selftests/jump-to-simple-return.rtl
new file mode 100644
index 0000000..ab27b85
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-simple-return.rtl
@@ -0,0 +1,11 @@
+(function "jump_to_simple_return"
+  (insn-chain
+    (jump_insn 1 0 2 4 (set (pc)
+        (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+    -> simple_return)
+    (barrier 2 1 3)
+    (code_label 3 2 0 5 2 (nil) [1 uses])
+  ) ;; insn-chain
+) ;; function
+
diff --git a/gcc/testsuite/selftests/note-insn-deleted.rtl b/gcc/testsuite/selftests/note-insn-deleted.rtl
new file mode 100644
index 0000000..baf36cc
--- /dev/null
+++ b/gcc/testsuite/selftests/note-insn-deleted.rtl
@@ -0,0 +1,5 @@
+(function "example_note"
+  (insn-chain
+    (note 1 0 0 (nil) NOTE_INSN_DELETED)
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/note_insn_basic_block.rtl b/gcc/testsuite/selftests/note_insn_basic_block.rtl
new file mode 100644
index 0000000..11eb14d
--- /dev/null
+++ b/gcc/testsuite/selftests/note_insn_basic_block.rtl
@@ -0,0 +1,5 @@
+(function "example_of_note"
+  (insn-chain
+     (note 1 0 0 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/symbol-ref.rtl b/gcc/testsuite/selftests/symbol-ref.rtl
new file mode 100644
index 0000000..226295d
--- /dev/null
+++ b/gcc/testsuite/selftests/symbol-ref.rtl
@@ -0,0 +1,7 @@
+(function "example_of_symbol_ref"
+  (insn-chain
+    (insn 1045 0 0 2 (set (reg:SI 480)
+        (high:SI (symbol_ref:SI ("isl_obj_map_vtable") [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>))) y.c:12702 -1
+     (nil))
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/test-regno-renumbering.rtl b/gcc/testsuite/selftests/test-regno-renumbering.rtl
new file mode 100644
index 0000000..007666f
--- /dev/null
+++ b/gcc/testsuite/selftests/test-regno-renumbering.rtl
@@ -0,0 +1,6 @@
+(function "test"
+  (insn-chain
+    ;; The regs here have no names and are thus to be treated as pseudos.
+    (insn 1 0 0 2 (set (reg:SI 10) (reg:SI 11)) -1 (nil))
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/x86_64/call-insn.rtl b/gcc/testsuite/selftests/x86_64/call-insn.rtl
new file mode 100644
index 0000000..b3be835
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/call-insn.rtl
@@ -0,0 +1,12 @@
+(function "test"
+  (insn-chain
+    (call_insn/j 17 0 0 2 (set (reg:DF 21 xmm0)
+                (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
+                    (const_int 0 [0]))) test.c:19 -1
+             (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>)
+                (expr_list:REG_EH_REGION (const_int 0 [0])
+                    (nil)))
+            (expr_list:DF (use (reg:DF 21 xmm0))
+                (nil)))
+  ) ;; insn-chain
+) ;; function "test"
diff --git a/gcc/testsuite/selftests/x86_64/times-two.rtl b/gcc/testsuite/selftests/x86_64/times-two.rtl
new file mode 100644
index 0000000..9eaee45
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/times-two.rtl
@@ -0,0 +1,57 @@
+;; Dump of this C function:
+;;
+;; int times_two (int i)
+;; {
+;;   return i * 2;
+;; }
+;;
+;; after expand for target==x86_64
+
+(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"
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 9a3b072..ec63b34 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -305,6 +305,11 @@ ssa_default_def (struct function *fn, tree var)
   gcc_assert (TREE_CODE (var) == VAR_DECL
 	      || TREE_CODE (var) == PARM_DECL
 	      || TREE_CODE (var) == RESULT_DECL);
+
+  /* Always NULL_TREE for rtl function dumps.  */
+  if (!fn->gimple_df)
+    return NULL_TREE;
+
   in.var = (tree)&ind;
   ind.uid = DECL_UID (var);
   return DEFAULT_DEFS (fn)->find_with_hash ((tree)&in, DECL_UID (var));
-- 
1.8.5.3

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

* [PATCH 12/16] combine.c selftests (v2)
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (5 preceding siblings ...)
  2016-10-05 15:45 ` [PATCH 13/16] cse.c selftests David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-05 15:45 ` [PATCH 10/16] Introduce class function_reader (v3) David Malcolm
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Changed in v2:
* moved dumps from a string literal to external files (sharing
a dump with read-rtl-function.c)
* update for addition of selftest::location to rtl_dump_test

gcc/ChangeLog:
	* combine.c: Include selftest.h and selftest-rtl.h.
	(try_combine): Add assertion on this_basic_block.
	(class selftest::combine_test): New subclass of
	selftest::tl_dump_test.
	(selftest::combine_test::combine_test): New ctor.
	(selftest::test_combining_shifts): New function.
	(selftest::test_non_combinable_shifts): New function.
	(selftest::combine_c_tests): New function.
	* selftest-run-tests.c (selftest::run_tests): Run
	selftest::combine_c_tests.
	* selftest.h (selftest::combine_c_tests): New decl.

gcc/testsuite/ChangeLog:
	* selftests/non-combinable-shifts.rtl: New file.
---
 gcc/combine.c                                     | 121 ++++++++++++++++++++++
 gcc/selftest-run-tests.c                          |   1 +
 gcc/selftest.h                                    |   1 +
 gcc/testsuite/selftests/non-combinable-shifts.rtl |  18 ++++
 4 files changed, 141 insertions(+)
 create mode 100644 gcc/testsuite/selftests/non-combinable-shifts.rtl

diff --git a/gcc/combine.c b/gcc/combine.c
index b27aae5..ad1655e 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -102,6 +102,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "valtrack.h"
 #include "rtl-iter.h"
 #include "print-rtl.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
 
 #ifndef LOAD_EXTEND_OP
 #define LOAD_EXTEND_OP(M) UNKNOWN
@@ -2625,6 +2627,8 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
   rtx new_other_notes;
   int i;
 
+  gcc_assert (this_basic_block);
+
   /* Immediately return if any of I0,I1,I2 are the same insn (I3 can
      never be).  */
   if (i1 == i2 || i0 == i2 || (i0 && i0 == i1))
@@ -14443,3 +14447,120 @@ make_pass_combine (gcc::context *ctxt)
 {
   return new pass_combine (ctxt);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* A subclass of rtl_dump_test for testing combine.c.  */
+
+class combine_test : public rtl_dump_test
+{
+ public:
+  combine_test (const location &loc, char *path);
+
+ private:
+   dataflow_test m_df_test;
+};
+
+/* combine_test's constructor.  Read dumped RTL function from PATH,
+   taking ownership of PATH.
+   Initialize df and perform dataflow analysis.  */
+
+combine_test::combine_test (const location &loc, char *path)
+: rtl_dump_test (loc, path),
+  m_df_test ()
+{
+  /* The dataflow instance should have been created by m_df_test's ctor.  */
+  gcc_assert (df);
+
+  /* From rest_of_handle_combine.  */
+  df_set_flags (/*DF_LR_RUN_DCE + */ DF_DEFER_INSN_RESCAN);
+  df_note_add_problem ();
+  df_analyze ();
+}
+
+/* Verify that combine_instructions works, for combining a pair of shifts.
+   Ideally we'd test try_combine by itself, but a fair amount of
+   refactoring would be needed to do so.  */
+
+static void
+test_combining_shifts ()
+{
+  combine_test t (SELFTEST_LOCATION, locate_file ("asr_div1.rtl"));
+
+  rtx_insn *insn_8 = get_insn_by_uid (8);
+  ASSERT_TRUE (insn_8);
+
+  rtx_insn *insn_9 = get_insn_by_uid (9);
+  ASSERT_TRUE (insn_9);
+
+  int rebuild_jump_labels_after_combine
+    = combine_instructions (get_insns (), max_reg_num ());
+  ASSERT_FALSE (rebuild_jump_labels_after_combine);
+
+  /* Verify that insns 8 and 9 were combined.  */
+  ASSERT_EQ (1, combine_merges);
+
+  /* insn 8 should now be deleted.  */
+  ASSERT_EQ (NOTE, GET_CODE (insn_8));
+  ASSERT_EQ (NOTE_INSN_DELETED, NOTE_KIND (insn_8));
+
+  /* insn 9 should now be a shift of 35.
+     On aarch64 it's a set; on x86_64 it's a parallel of a set and a clobber
+     of CC.  */
+  rtx set_in_9 = single_set (insn_9);
+  ASSERT_TRUE (set_in_9);
+  rtx src_of_9 = SET_SRC (set_in_9);
+  ASSERT_EQ (ASHIFTRT, GET_CODE (src_of_9));
+  rtx amt = XEXP (src_of_9, 1);
+  ASSERT_TRUE (CONST_INT_P (amt));
+  ASSERT_EQ (35, INTVAL (amt));
+}
+
+/* Test of failing to combine instructions.
+
+   Similar to test_combining_shifts, but with the input register
+   for the 2nd shift hand-edited (from 78 to 80) so that it doesn't come
+   from the output of the 1st shift, so that the shifts should *not*
+   be combinable.  */
+
+static void
+test_non_combinable_shifts ()
+{
+  combine_test t (SELFTEST_LOCATION, locate_file ("non-combinable-shifts.rtl"));
+
+  rtx_insn *insn_8 = get_insn_by_uid (8);
+  ASSERT_TRUE (insn_8);
+
+  rtx_insn *insn_9 = get_insn_by_uid (9);
+  ASSERT_TRUE (insn_9);
+
+  int rebuild_jump_labels_after_combine
+    = combine_instructions (get_insns (), max_reg_num ());
+  ASSERT_FALSE (rebuild_jump_labels_after_combine);
+
+  /* Verify that no insns were combined.  */
+  ASSERT_EQ (0, combine_merges);
+
+  /* insn 8 should not have be touched.  */
+  ASSERT_EQ (INSN, GET_CODE (insn_8));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+combine_c_tests ()
+{
+  /* Only run these tests for i386.  */
+#ifndef I386_OPTS_H
+  return;
+#endif
+
+  test_combining_shifts ();
+  test_non_combinable_shifts ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 5c95aaa..a10657f 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -75,6 +75,7 @@ selftest::run_tests ()
 
   /* Higher-level tests, or for components that other selftests don't
      rely on.  */
+  combine_c_tests ();
   diagnostic_show_locus_c_tests ();
   diagnostic_c_tests ();
   edit_context_c_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 0033942..95bf9b2 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -200,6 +200,7 @@ extern const char *path_to_src_gcc;
 /* Declarations for specific families of tests (by source file), in
    alphabetical order.  */
 extern void bitmap_c_tests ();
+extern void combine_c_tests ();
 extern void df_core_c_tests ();
 extern void diagnostic_c_tests ();
 extern void diagnostic_show_locus_c_tests ();
diff --git a/gcc/testsuite/selftests/non-combinable-shifts.rtl b/gcc/testsuite/selftests/non-combinable-shifts.rtl
new file mode 100644
index 0000000..87da195
--- /dev/null
+++ b/gcc/testsuite/selftests/non-combinable-shifts.rtl
@@ -0,0 +1,18 @@
+(function "test"
+  (insn-chain
+(insn 8 0 9 2 (set (reg:DI 78)
+        (lshiftrt:DI (reg:DI 76)
+            (const_int 32 [0x20])))
+        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14
+        641 {*aarch64_lshr_sisd_or_int_di3}
+     (expr_list:REG_DEAD (reg:DI 76)
+        (nil)))
+(insn 9 8 0 2 (set (reg:SI 79)
+        (ashiftrt:SI (subreg:SI (reg:DI 80) 0)
+            (const_int 3 [0x3])))
+        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14
+        642 {*aarch64_ashr_sisd_or_int_si3}
+     (expr_list:REG_DEAD (reg:DI 78)
+        (nil)))
+  ) ;; insn-chain
+) ;; function
-- 
1.8.5.3

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

* [PATCH 02/16] (approved) Add selftest::read_file
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (3 preceding siblings ...)
  2016-10-05 15:44 ` [PATCH 01/16] read-md.c: Add various cleanups to ~rtx_reader David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-05 15:45 ` [PATCH 13/16] cse.c selftests David Malcolm
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Jeff: "Seems reasonable.  Install when you have a need."

This is used later in the kit by the selftests for final.c

gcc/ChangeLog:
	* selftest.c (selftest::read_file): New function.
	(selftest::test_read_file): New function.
	(selftest::selftest_c_tests): Call test_read_file.
	* selftest.h (selftest::read_file): New decl.
---
 gcc/selftest.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/selftest.h |  7 +++++++
 2 files changed, 67 insertions(+)

diff --git a/gcc/selftest.c b/gcc/selftest.c
index 0db69d2..cf7031f 100644
--- a/gcc/selftest.c
+++ b/gcc/selftest.c
@@ -151,6 +151,53 @@ temp_source_file::temp_source_file (const location &loc,
   fclose (out);
 }
 
+/* Read the contents of PATH into memory, returning a 0-terminated buffer
+   that must be freed by the caller.
+   Fail (and abort) if there are any problems, with LOC as the reported
+   location of the failure.  */
+
+char *
+read_file (const location &loc, const char *path)
+{
+  FILE *f_in = fopen (path, "r");
+  if (!f_in)
+    fail_formatted (loc, "unable to open file: %s", path);
+
+  /* Read content, allocating FIXME.  */
+  char *result = NULL;
+  size_t total_sz = 0;
+  size_t alloc_sz = 0;
+  char buf[4096];
+  size_t iter_sz_in;
+
+  while ( (iter_sz_in = fread (buf, 1, sizeof (buf), f_in)) )
+    {
+      gcc_assert (alloc_sz >= total_sz);
+      size_t old_total_sz = total_sz;
+      total_sz += iter_sz_in;
+      /* Allow 1 extra byte for 0-termination.  */
+      if (alloc_sz < (total_sz + 1))
+	{
+	  size_t new_alloc_sz = alloc_sz ? alloc_sz * 2: total_sz + 1;
+	  result = (char *)xrealloc (result, new_alloc_sz);
+	  alloc_sz = new_alloc_sz;
+	}
+      memcpy (result + old_total_sz, buf, iter_sz_in);
+    }
+
+  if (!feof (f_in))
+    fail_formatted (loc, "error reading from %s: %s", path,
+		    xstrerror (errno));
+
+  fclose (f_in);
+
+  /* 0-terminate the buffer.  */
+  gcc_assert (total_sz < alloc_sz);
+  result[total_sz] = '\0';
+
+  return result;
+}
+
 /* Selftests for the selftest system itself.  */
 
 /* Sanity-check the ASSERT_ macros with various passing cases.  */
@@ -181,6 +228,18 @@ test_named_temp_file ()
   fclose (f);
 }
 
+/* Verify read_file (and also temp_source_file).  */
+
+static void
+test_read_file ()
+{
+  temp_source_file t (SELFTEST_LOCATION, "test1.s",
+		      "\tjmp\t.L2\n");
+  char *buf = read_file (SELFTEST_LOCATION, t.get_filename ());
+  ASSERT_STREQ ("\tjmp\t.L2\n", buf);
+  free (buf);
+}
+
 /* Run all of the selftests within this file.  */
 
 void
@@ -188,6 +247,7 @@ selftest_c_tests ()
 {
   test_assertions ();
   test_named_temp_file ();
+  test_read_file ();
 }
 
 } // namespace selftest
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 3938560..e5f5c60 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -146,6 +146,13 @@ class line_table_test
 extern void
 for_each_line_table_case (void (*testcase) (const line_table_case &));
 
+/* Read the contents of PATH into memory, returning a 0-terminated buffer
+   that must be freed by the caller.
+   Fail (and abort) if there are any problems, with LOC as the reported
+   location of the failure.  */
+
+extern char *read_file (const location &loc, const char *path);
+
 /* Declarations for specific families of tests (by source file), in
    alphabetical order.  */
 extern void bitmap_c_tests ();
-- 
1.8.5.3

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

* [PATCH 03/16] (approved) selftest.h: add temp_override fixture
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (11 preceding siblings ...)
  2016-10-05 15:45 ` [PATCH 09/16] Split class rtx_reader into base_rtx_reader vs rtx_reader David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-05 15:45 ` [PATCH 06/16] Introduce emit_status::ensure_regno_capacity David Malcolm
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Jeff: "When you need it, this is fine."

We have a lot of global state in our code.  Ideally we'd reduce the
amount of such global state, but a prerequisite for sane refactoring
is having automated testing in place to ensure that the refactoring
doesn't break anything.

However, the global state itself makes it hard to write such automated
testing.

To break this Catch-22, this patch introduces a class temp_override,
for temporarily assigning a value to a global variable, saving the old
value, and then restoring that old value in a dtor.

gcc/ChangeLog:
	* selftest.h (selftest::temp_override): New class.
---
 gcc/selftest.h | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/gcc/selftest.h b/gcc/selftest.h
index e5f5c60..4c50217 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -153,6 +153,35 @@ for_each_line_table_case (void (*testcase) (const line_table_case &));
 
 extern char *read_file (const location &loc, const char *path);
 
+/* A fixture for temporarily overriding a global variable with a new
+   value.  The original value of the variable is captured in the ctor,
+   and restored in the dtor.  */
+
+template <typename T>
+class temp_override
+{
+ public:
+  temp_override (T& var, T new_value)
+  : m_var (var),
+    /* Record the current value of VAR.  */
+    m_old_value (var)
+  {
+    /* Set the var to the new value.  */
+    m_var = new_value;
+  }
+
+  ~temp_override ()
+  {
+    /* Restore the value of the variable to that stored in the
+       ctor.  */
+    m_var = m_old_value;
+  }
+
+ private:
+  T& m_var;
+  T m_old_value;
+};
+
 /* Declarations for specific families of tests (by source file), in
    alphabetical order.  */
 extern void bitmap_c_tests ();
-- 
1.8.5.3

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

* [PATCH 04/16] (approved) Expose forcibly_ggc_collect and run it after all selftests
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (13 preceding siblings ...)
  2016-10-05 15:45 ` [PATCH 06/16] Introduce emit_status::ensure_regno_capacity David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-05 15:45 ` [PATCH 16/16] Add "__RTL" to cc1 David Malcolm
  15 siblings, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Jeff:
> Seems reasonable and doesn't depend on earlier patches, right?
> Assuming that's correct it seems fine for the trunk whenever you want to
> install it.

gcc/ChangeLog:
	* ggc-tests.c (forcibly_ggc_collect): Rename to...
	(selftest::forcibly_ggc_collect): ...this, and remove "static".
	(test_basic_struct): Update for above renaming.
	(test_length): Likewise.
	(test_union): Likewise.
	(test_finalization): Likewise.
	(test_deletable_global): Likewise.
	(test_inheritance): Likewise.
	(test_chain_next): Likewise.
	(test_user_struct): Likewise.
	(test_tree_marking): Likewise.
	* selftest-run-tests.c (selftest::run_tests): Call
	selftest::forcibly_ggc_collect at the end of the selftests.
	* selftest.h (selftest::forcibly_ggc_collect): New decl.
---
 gcc/ggc-tests.c          | 28 ++++++++++++++--------------
 gcc/selftest-run-tests.c |  6 ++++++
 gcc/selftest.h           |  5 +++++
 3 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/gcc/ggc-tests.c b/gcc/ggc-tests.c
index 7f97231..b9cd276 100644
--- a/gcc/ggc-tests.c
+++ b/gcc/ggc-tests.c
@@ -27,19 +27,19 @@ along with GCC; see the file COPYING3.  If not see
 
 #if CHECKING_P
 
-/* The various GTY markers must be outside of a namespace to be seen by
-   gengtype, so we don't put this file within the selftest namespace.  */
-
 /* A helper function for writing ggc tests.  */
 
-static void
-forcibly_ggc_collect ()
+void
+selftest::forcibly_ggc_collect ()
 {
   ggc_force_collect = true;
   ggc_collect ();
   ggc_force_collect = false;
 }
 
+/* The various GTY markers must be outside of a namespace to be seen by
+   gengtype, so we don't put this file within the selftest namespace.  */
+
 \f
 
 /* Verify that a simple struct works, and that it can
@@ -58,7 +58,7 @@ test_basic_struct ()
   root_test_struct = ggc_cleared_alloc <test_struct> ();
   root_test_struct->other = ggc_cleared_alloc <test_struct> ();
 
-  forcibly_ggc_collect ();
+  selftest::forcibly_ggc_collect ();
 
   ASSERT_TRUE (ggc_marked_p (root_test_struct));
   ASSERT_TRUE (ggc_marked_p (root_test_struct->other));
@@ -88,7 +88,7 @@ test_length ()
   for (int i = 0; i < count; i++)
     root_test_of_length->elem[i] = ggc_cleared_alloc <test_of_length> ();
 
-  forcibly_ggc_collect ();
+  selftest::forcibly_ggc_collect ();
 
   ASSERT_TRUE (ggc_marked_p (root_test_of_length));
   for (int i = 0; i < count; i++)
@@ -162,7 +162,7 @@ test_union ()
   test_struct *referenced_by_other = ggc_cleared_alloc <test_struct> ();
   other->m_ptr = referenced_by_other;
 
-  forcibly_ggc_collect ();
+  selftest::forcibly_ggc_collect ();
 
   ASSERT_TRUE (ggc_marked_p (root_test_of_union_1));
   ASSERT_TRUE (ggc_marked_p (ts));
@@ -202,7 +202,7 @@ test_finalization ()
 
   test_struct_with_dtor::dtor_call_count = 0;
 
-  forcibly_ggc_collect ();
+  selftest::forcibly_ggc_collect ();
 
   /* Verify that the destructor was run for each instance.  */
   ASSERT_EQ (count, test_struct_with_dtor::dtor_call_count);
@@ -220,7 +220,7 @@ test_deletable_global ()
   test_of_deletable = ggc_cleared_alloc <test_struct> ();
   ASSERT_TRUE (test_of_deletable != NULL);
 
-  forcibly_ggc_collect ();
+  selftest::forcibly_ggc_collect ();
 
   ASSERT_EQ (NULL, test_of_deletable);
 }
@@ -293,7 +293,7 @@ test_inheritance ()
   test_some_subclass_as_base_ptr = new some_subclass ();
   test_some_other_subclass_as_base_ptr = new some_other_subclass ();
 
-  forcibly_ggc_collect ();
+  selftest::forcibly_ggc_collect ();
 
   /* Verify that the roots and everything referenced by them got marked
      (both for fields in the base class and those in subclasses).  */
@@ -372,7 +372,7 @@ test_chain_next ()
       tail_node = new_node;
     }
 
-  forcibly_ggc_collect ();
+  selftest::forcibly_ggc_collect ();
 
   /* If we got here, we survived.  */
 
@@ -439,7 +439,7 @@ test_user_struct ()
 
   num_calls_to_user_gt_ggc_mx = 0;
 
-  forcibly_ggc_collect ();
+  selftest::forcibly_ggc_collect ();
 
   ASSERT_TRUE (ggc_marked_p (root_user_struct_ptr));
   ASSERT_TRUE (ggc_marked_p (referenced));
@@ -457,7 +457,7 @@ test_tree_marking ()
 {
   dummy_unittesting_tree = build_int_cst (integer_type_node, 1066);
 
-  forcibly_ggc_collect ();
+  selftest::forcibly_ggc_collect ();
 
   ASSERT_TRUE (ggc_marked_p (dummy_unittesting_tree));
 }
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index d9d3ea1..54a9b0f 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -80,6 +80,12 @@ selftest::run_tests ()
   /* Run any lang-specific selftests.  */
   lang_hooks.run_lang_selftests ();
 
+  /* Force a GC at the end of the selftests, to shake out GC-related
+     issues.  For example, if any GC-managed items have buggy (or missing)
+     finalizers, this last collection will ensure that things that were
+     failed to be finalized can be detected by valgrind.  */
+  forcibly_ggc_collect ();
+
   /* Finished running tests.  */
   long finish_time = get_run_time ();
   long elapsed_time = finish_time - start_time;
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 4c50217..86ad14c 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -182,6 +182,11 @@ class temp_override
   T m_old_value;
 };
 
+/* A helper function for writing tests that interact with the
+   garbage collector.  */
+
+extern void forcibly_ggc_collect ();
+
 /* Declarations for specific families of tests (by source file), in
    alphabetical order.  */
 extern void bitmap_c_tests ();
-- 
1.8.5.3

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

* [PATCH 14/16] RTL interpreter (work-in-progress)
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (9 preceding siblings ...)
  2016-10-05 15:45 ` [PATCH 15/16] RTL frontend (rtl1), on top of dump reader David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-05 15:45 ` [PATCH 09/16] Split class rtx_reader into base_rtx_reader vs rtx_reader David Malcolm
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

This patch is much less polished than the rest of the kit; it's
more of an idea, showing an RTL interpreter.  My hope is that
something like this could be used to build a valgrind for RTL,
allowing us to run RTL fragments with a variety of inputs, for
sanity checking.

For example: capture the result of an RTL function on various inputs,
run an optimization pass, then verify that the results are sufficiently
similar to before, potentially auto-detecting.

(could have a gdb stub, for connecting to the interpreter and stepping
through RTL)

(Clearly a lot of hand-waving here; the patch itself is full of FIXMEs).

gcc/ChangeLog:
	* Makefile.in (OBJS): Add rtl-interpreter.o.
	* rtl-interpreter.c: New file.
	* rtl-interpreter.h: New file.
	* selftest-run-tests.c (selftest::run_tests): Add call to
	rtl_interpreter_c_tests.
	* selftest.h (selftest::rtl_interpreter_c_tests): New decl.

gcc/testsuite/ChangeLog:
	* selftests/rtl/interp/empty-function.rtl: New file.
	* selftests/rtl/interp/simple-arith.rtl: New file.
	* selftests/rtl/interp/simple-set.rtl: New file.
	* selftests/rtl/interp/undefined-read.rtl: New file.
---
 gcc/Makefile.in                                    |   1 +
 gcc/rtl-interpreter.c                              | 371 +++++++++++++++++++++
 gcc/rtl-interpreter.h                              |  86 +++++
 gcc/selftest-run-tests.c                           |   1 +
 gcc/selftest.h                                     |   1 +
 .../selftests/rtl/interp/empty-function.rtl        |  19 ++
 .../selftests/rtl/interp/simple-arith.rtl          |  13 +
 gcc/testsuite/selftests/rtl/interp/simple-set.rtl  |   7 +
 .../selftests/rtl/interp/undefined-read.rtl        |  11 +
 9 files changed, 510 insertions(+)
 create mode 100644 gcc/rtl-interpreter.c
 create mode 100644 gcc/rtl-interpreter.h
 create mode 100644 gcc/testsuite/selftests/rtl/interp/empty-function.rtl
 create mode 100644 gcc/testsuite/selftests/rtl/interp/simple-arith.rtl
 create mode 100644 gcc/testsuite/selftests/rtl/interp/simple-set.rtl
 create mode 100644 gcc/testsuite/selftests/rtl/interp/undefined-read.rtl

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7c8df56..3582bde 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1426,6 +1426,7 @@ OBJS = \
 	resource.o \
 	rtl-chkp.o \
 	rtl-error.o \
+	rtl-interpreter.o \
 	rtl-tests.o \
 	rtl.o \
 	rtlhash.o \
diff --git a/gcc/rtl-interpreter.c b/gcc/rtl-interpreter.c
new file mode 100644
index 0000000..9c9d48d
--- /dev/null
+++ b/gcc/rtl-interpreter.c
@@ -0,0 +1,371 @@
+/* RTL interpreter.
+   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 "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "emit-rtl.h"
+#include "rtl-interpreter.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
+
+static rtl_value::value_t
+get_defined_bits (enum machine_mode mode)
+{
+  switch (mode)
+    {
+    case VOIDmode: // FIXME
+    case SImode:
+      return (1ul << 32) - 1;
+
+    default:
+      abort (); // unhandled
+      break;
+    }
+}
+
+/* FIXME.  */
+
+rtl_value::rtl_value (enum machine_mode mode, value_t value, value_t defined_bits)
+: m_mode (mode), m_value (value), m_defined_bits (defined_bits)
+{
+}
+
+
+/* FIXME.  */
+
+rtl_value
+rtl_state::eval (rtx x) const
+{
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      return rtl_value (GET_MODE (x), INTVAL (x),
+			get_defined_bits (GET_MODE (x)));
+
+    case REG:
+      // FIXME: apply mode
+      return get_reg_value (REGNO (x));
+
+    case PLUS:
+      {
+	rtl_value lhs = eval (XEXP (x, 0));
+	rtl_value rhs = eval (XEXP (x, 1));
+	return rtl_value (GET_MODE (x),
+			  lhs.m_value + rhs.m_value,
+			  // FIXME:
+			  lhs.m_defined_bits & rhs.m_defined_bits);
+      }
+      break;
+
+    case SUBREG:
+      {
+	rtl_value complete = eval (XEXP (x, 0));
+	int offset = XINT (x, 1);
+	gcc_assert (offset == 0); // TODO: for now
+
+	// TODO: apply offset to complete.m_value
+
+	rtl_value::value_t subreg_bits = get_defined_bits (GET_MODE (x));
+	// TODO: apply offset to subreg_bits
+	complete.m_defined_bits &= subreg_bits;
+	return complete;
+      }
+
+    default:
+      abort (); // unhandled
+      break;
+    }
+}
+
+/* FIXME.  */
+
+rtl_value
+rtl_state::get_reg_value (int regno) const
+{
+  rtl_value *value = const_cast <rtl_state *> (this)->m_reg_values.get (regno);
+  if (value)
+    return *value;
+  else
+    abort (); // FIXME
+}
+
+/* FIXME.  */
+
+void
+rtl_state::set_reg_value (int regno, const rtl_value &value)
+{
+  m_reg_values.put (regno, value);
+}
+
+/* FIXME.  */
+
+void
+rtl_state::debug () const
+{
+  for (reg_value_iterator_t iter = m_reg_values.begin ();
+       iter != m_reg_values.end ();
+       ++iter)
+    {
+      int regno = (*iter).first;
+      rtl_value value = (*iter).second;
+
+      fprintf (stdout, "r%d: %d\n", regno, (int)value.m_value);
+    }
+}
+
+/* FIXME.  */
+
+rtl_interpreter::rtl_interpreter (rtx_insn *insn, rtl_state *state)
+: m_cur_insn (insn), m_state (state)
+{
+}
+
+/* FIXME.  */
+
+void
+rtl_interpreter::run_insn ()
+{
+  gcc_assert (m_cur_insn);
+
+  rtx_insn *next_insn = NEXT_INSN (m_cur_insn);
+
+  switch (GET_CODE (m_cur_insn))
+    {
+    case DEBUG_INSN:
+      on_debug_insn (as_a <rtx_debug_insn *> ((rtx)m_cur_insn));
+      break;
+
+    case INSN:
+      on_nonjump_insn (as_a <rtx_nonjump_insn *> ((rtx)m_cur_insn));
+      break;
+
+    case JUMP_INSN:
+      next_insn = on_jump_insn (as_a <rtx_jump_insn *> ((rtx)m_cur_insn));
+      break;
+
+    case CALL_INSN:
+      on_call_insn (as_a <rtx_call_insn *> ((rtx)m_cur_insn));
+      break;
+
+    case JUMP_TABLE_DATA:
+      on_jump_table_data (as_a <rtx_jump_table_data *> ((rtx)m_cur_insn));
+      break;
+
+    case BARRIER:
+      on_barrier (as_a <rtx_barrier *> ((rtx)m_cur_insn));
+      break;
+
+    case CODE_LABEL:
+      on_code_label (as_a <rtx_code_label *> ((rtx)m_cur_insn));
+      break;
+
+    case NOTE:
+      on_note (as_a <rtx_note *> ((rtx)m_cur_insn));
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  m_cur_insn = next_insn;
+}
+
+void
+rtl_interpreter::on_debug_insn (rtx_debug_insn *)
+{
+  /* no-op */
+}
+
+void
+rtl_interpreter::on_nonjump_insn (rtx_nonjump_insn *insn)
+{
+  rtx pat = PATTERN (insn);
+  switch (GET_CODE (pat))
+    {
+    case SET:
+      {
+	rtx src = SET_SRC (pat);
+	rtx dest = SET_DEST (pat);
+	switch (GET_CODE (dest))
+	  {
+	  case REG:
+	    {
+	      rtl_value new_value = m_state->eval (src);
+	      m_state->set_reg_value (REGNO (dest), new_value);
+	    }
+	    break;
+
+	  default:
+	    abort (); // unhandled
+	    break;
+	  }
+	// TODO
+      }
+      break;
+
+    default:
+      break;
+    }
+}
+
+rtx_insn *
+rtl_interpreter::on_jump_insn (rtx_jump_insn *insn)
+{
+  rtx pat = PATTERN (insn);
+  if (pat == simple_return_rtx)
+    return NULL;
+  abort (); // unimplemented
+  return NEXT_INSN (m_cur_insn); // FIXME
+}
+
+void
+rtl_interpreter::on_call_insn (rtx_call_insn *)
+{
+  /* no-op */
+}
+
+void
+rtl_interpreter::on_jump_table_data (rtx_jump_table_data *)
+{
+  /* no-op */
+}
+
+void
+rtl_interpreter::on_barrier (rtx_barrier *)
+{
+  /* no-op */
+}
+
+void
+rtl_interpreter::on_code_label (rtx_code_label *)
+{
+  /* no-op */
+}
+
+void
+rtl_interpreter::on_note (rtx_note *)
+{
+  /* no-op */
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for RTL interpreter.  */
+
+/* Verify interpreting an empty function.  */
+
+static void
+test_interpret_empty_function ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION,
+		   locate_file ("rtl/interp/empty-function.rtl"));
+  rtl_state state;
+  rtl_interpreter interp (get_insns (), &state);
+  ASSERT_EQ (1, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  ASSERT_EQ (3, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  ASSERT_EQ (8, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  ASSERT_EQ (2, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  ASSERT_EQ (9, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  ASSERT_EQ (10, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  ASSERT_EQ (NULL, interp.get_cur_insn ());
+}
+
+/* FIXME.  */
+
+static void
+test_interpret_simple_set ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION,
+		   locate_file ("rtl/interp/simple-set.rtl"));
+  rtl_state state;
+  rtl_interpreter interp (get_insns (), &state);
+  ASSERT_EQ (100, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  ASSERT_EQ (NULL, interp.get_cur_insn ());
+  ASSERT_EQ (42, state.get_reg_value (100).m_value);
+  ASSERT_EQ (0xffffffff, state.get_reg_value (100).m_defined_bits);
+}
+
+/* FIXME.  */
+
+static void
+test_interpret_simple_arith ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION,
+		   locate_file ("rtl/interp/simple-arith.rtl"));
+  rtl_state state;
+  rtl_interpreter interp (get_insns (), &state);
+  ASSERT_EQ (100, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  ASSERT_EQ (5, state.get_reg_value (100).m_value);
+  ASSERT_EQ (101, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  ASSERT_EQ (3, state.get_reg_value (101).m_value);
+  ASSERT_EQ (102, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  ASSERT_EQ (8, state.get_reg_value (102).m_value);
+  ASSERT_EQ (0xffffffff, state.get_reg_value (102).m_defined_bits);
+  ASSERT_EQ (NULL, interp.get_cur_insn ());
+  state.debug ();
+}
+
+/* FIXME.  */
+
+static void
+test_interpret_undefined_read ()
+{
+  // TODO: read from a paradoxical subreg, use of undefined bits
+  rtl_dump_test t (SELFTEST_LOCATION,
+		   locate_file ("rtl/interp/undefined-read.rtl"));
+  rtl_state state;
+  rtl_interpreter interp (get_insns (), &state);
+  ASSERT_EQ (100, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  ASSERT_EQ (42, state.get_reg_value (100).m_value);
+  ASSERT_EQ (101, INSN_UID (interp.get_cur_insn ()));
+  interp.run_insn ();
+  state.debug ();
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+rtl_interpreter_c_tests ()
+{
+  test_interpret_empty_function ();
+  test_interpret_simple_set ();
+  test_interpret_simple_arith ();
+  test_interpret_undefined_read ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/rtl-interpreter.h b/gcc/rtl-interpreter.h
new file mode 100644
index 0000000..4e33ed5
--- /dev/null
+++ b/gcc/rtl-interpreter.h
@@ -0,0 +1,86 @@
+/* RTL interpreter.
+   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/>.  */
+
+#ifndef GCC_RTL_INTERPRETER_H
+#define GCC_RTL_INTERPRETER_H
+
+class rtl_state;
+class rtl_interpreter;
+
+/* FIXME.  */
+
+class rtl_value
+{
+ public:
+  typedef unsigned long long value_t;
+
+  rtl_value (enum machine_mode mode, value_t value, value_t defined_bits);
+
+#if 0
+  operator long () const { return m_value; }
+#endif
+
+  enum machine_mode m_mode;
+  value_t m_value;
+  value_t m_defined_bits;
+};
+
+class rtl_state
+{
+ public:
+  rtl_value eval (rtx expr) const;
+  rtl_value get_reg_value (int regno) const;
+  void set_reg_value (int regno, const rtl_value &value);
+
+  void debug () const;
+
+ private:
+  struct regno_hash : int_hash <int, -1, -2> {};
+  hash_map<regno_hash, rtl_value> m_reg_values;
+  typedef hash_map<regno_hash, rtl_value>::iterator reg_value_iterator_t;
+};
+
+/* FIXME.  */
+
+class rtl_interpreter
+{
+ public:
+  rtl_interpreter (rtx_insn *insn, rtl_state *state);
+  virtual ~rtl_interpreter () {}
+
+  void run_insn ();
+
+  rtx_insn *get_cur_insn () const { return m_cur_insn; }
+
+ private:
+  virtual void on_debug_insn (rtx_debug_insn *insn);
+  virtual void on_nonjump_insn (rtx_nonjump_insn *insn);
+  virtual rtx_insn *on_jump_insn (rtx_jump_insn *insn);
+  virtual void on_call_insn (rtx_call_insn *insn);
+  virtual void on_jump_table_data (rtx_jump_table_data *insn);
+  virtual void on_barrier (rtx_barrier *insn);
+  virtual void on_code_label (rtx_code_label *insn);
+  virtual void on_note (rtx_note *insn);
+
+ private:
+  rtx_insn *m_cur_insn;
+  rtl_state *m_state;
+};
+
+#endif  /* GCC_RTL_INTERPRETER_H  */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index f110a08..1856203 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -84,6 +84,7 @@ selftest::run_tests ()
   spellcheck_c_tests ();
   spellcheck_tree_c_tests ();
   tree_cfg_c_tests ();
+  rtl_interpreter_c_tests ();
 
   /* This one relies on most of the above.  */
   function_tests_c_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index e07fa26..8b1eb42 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -217,6 +217,7 @@ extern void hash_set_tests_c_tests ();
 extern void input_c_tests ();
 extern void pretty_print_c_tests ();
 extern void read_rtl_function_c_tests ();
+extern void rtl_interpreter_c_tests ();
 extern void rtl_tests_c_tests ();
 extern void selftest_c_tests ();
 extern void spellcheck_c_tests ();
diff --git a/gcc/testsuite/selftests/rtl/interp/empty-function.rtl b/gcc/testsuite/selftests/rtl/interp/empty-function.rtl
new file mode 100644
index 0000000..2783125
--- /dev/null
+++ b/gcc/testsuite/selftests/rtl/interp/empty-function.rtl
@@ -0,0 +1,19 @@
+;; Dump of the dump from cc1 in "test.c.289r.dwarf2" given this input:
+;;   void test_empty (void) {}
+;; and compiling with -Os (for x86_64).  */
+
+;; Function test_empty (test_empty, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+(function "test_empty"
+  (insn-chain
+    (note 1 0 3 (nil) NOTE_INSN_DELETED)
+    (note 3 1 8 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+    (note 8 3 2 2 NOTE_INSN_PROLOGUE_END)
+    (note 2 8 9 2 NOTE_INSN_FUNCTION_BEG)
+    (note 9 2 10 2 NOTE_INSN_EPILOGUE_BEG)
+    (jump_insn:TI 10 9 11 2 (simple_return) test.c:3 697 {simple_return_internal}
+     (nil)
+      -> simple_return)
+    (barrier 11 10 7)
+    (note 7 11 0 (nil) NOTE_INSN_DELETED)
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/rtl/interp/simple-arith.rtl b/gcc/testsuite/selftests/rtl/interp/simple-arith.rtl
new file mode 100644
index 0000000..1c3923f
--- /dev/null
+++ b/gcc/testsuite/selftests/rtl/interp/simple-arith.rtl
@@ -0,0 +1,13 @@
+(function "test"
+  (insn-chain
+    (insn 100 0 101 2
+      (set (reg:SI 100) (const_int 5 [0x5]))
+      test.c:2 -1 (nil))
+    (insn 101 100 102 2
+      (set (reg:SI 101) (const_int 3 [0x3]))
+      test.c:2 -1 (nil))
+    (insn 102 101 0 2
+      (set (reg:SI 102) (plus:SI (reg:SI 100) (reg:SI 101)))
+      test.c:2 -1 (nil))
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/rtl/interp/simple-set.rtl b/gcc/testsuite/selftests/rtl/interp/simple-set.rtl
new file mode 100644
index 0000000..0b6b00c
--- /dev/null
+++ b/gcc/testsuite/selftests/rtl/interp/simple-set.rtl
@@ -0,0 +1,7 @@
+(function "test"
+  (insn-chain
+    (insn 100 0 0 2
+      (set (reg:SI 100) (const_int 42 [0x2a]))
+          test.c:2 -1 (nil))
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/rtl/interp/undefined-read.rtl b/gcc/testsuite/selftests/rtl/interp/undefined-read.rtl
new file mode 100644
index 0000000..b817e31
--- /dev/null
+++ b/gcc/testsuite/selftests/rtl/interp/undefined-read.rtl
@@ -0,0 +1,11 @@
+(function "test"
+  (insn-chain
+    (insn 100 0 101 2
+      (set (reg:SI 100) (const_int 42 [0x42]))
+      test.c:2 -1 (nil))
+    ;; Read from paradoxical subreg leaves r101 partially undefined
+    (insn 101 100 0 2
+      (set (reg:SI 101) (subreg:SI (reg:HI 100) 0))
+      test.c:2 -1 (nil))
+  ) ;; insn-chain
+) ;; function
-- 
1.8.5.3

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

* [PATCH 09/16] Split class rtx_reader into base_rtx_reader vs rtx_reader
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (10 preceding siblings ...)
  2016-10-05 15:45 ` [PATCH 14/16] RTL interpreter (work-in-progress) David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-11 15:53   ` Bernd Schmidt
  2016-10-05 15:45 ` [PATCH 03/16] (approved) selftest.h: add temp_override fixture David Malcolm
                   ` (3 subsequent siblings)
  15 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

This moves read_rtx and friends into rtx_reader, and splits
rtx_reader into two classes:

class base_rtx_reader: has responsibility for reading chars, managing
include files, top-level directives etc.  It is the read-md.o part.

class rtx_reader, a subclass, has the code for reading hierarchical
rtx expressions using the format codes.   It is the read-rtl.o part.

This split is needed by a followup patch, which converts
read_rtx_operand to a virtual function of rtx_reader.  To do this,
instances of rtx_reader (or its subclasses) need a vtable, which
needs to include a ptr to the code in read-rtl.o.  Splitting it up
allows the gen* tools that currently purely use read-md.o to continue
to do so.

gcc/ChangeLog:
	* genpreds.c (write_tm_constrs_h): Update for renaming of
	rtx_reader_ptr to base_rtx_reader_ptr.
	(write_tm_preds_h): Likewise.
	(write_insn_preds_c): Likewise.
	* read-md.c (rtx_reader_ptr): Rename to...
	(base_rtx_reader_ptr): ...this, and convert
	from an rtx_reader * to a base_rtx_reader *.
	(fatal_with_file_and_line): Update for renaming of
	rtx_reader_ptr to base_rtx_reader_ptr.
	(rtx_reader::read_char): Rename to...
	(base_rtx_reader::read_char):... this.
	(rtx_reader::unread_char): Rename to...
	(base_rtx_reader::unread_char):... this.
	(read_escape): Update for renaming of rtx_reader_ptr to
	base_rtx_reader_ptr.
	(read_braced_string): Likewise.
	(read_string): Likewise.
	(rtx_reader::rtx_reader): Rename to...
	(base_rtx_reader::base_rtx_reader): ...this, and update for
	renaming of rtx_reader_ptr to base_rtx_reader_ptr.
	(rtx_reader::~rtx_reader): Rename to...
	(base_rtx_reader::~base_rtx_reader): ...this, and update for
	renaming of rtx_reader_ptr to base_rtx_reader_ptr.
	(rtx_reader::handle_include): Rename to...
	(base_rtx_reader::handle_include): ...this.
	(rtx_reader::handle_file): Rename to...
	(base_rtx_reader::handle_file): ...this.
	(rtx_reader::handle_toplevel_file): Rename to...
	(base_rtx_reader::handle_toplevel_file): ...this.
	(rtx_reader::get_current_location): Rename to...
	(base_rtx_reader::get_current_location): ...this.
	(rtx_reader::add_include_path): Rename to...
	(base_rtx_reader::add_include_path): ...this.
	(rtx_reader::read_md_files): Rename to...
	(base_rtx_reader::read_md_files): ...this.
	* read-md.h (struct enum_type {): Likewise.
	(class rtx_reader): Split into...
	(class base_rtx_reader): ...new class.
	(rtx_reader_ptr): Rename to...
	(base_rtx_reader_ptr): ...this, and convert to a
	base_rtx_reader *.
	(class noop_reader): Update base class to be base_rtx_reader.
	(class rtx_reader): Reintroduce as a subclass of base_rtx_reader.
	(rtx_reader_ptr): Reintroduce as a rtx_reader *.
	(read_char): Update for renaming of rtx_reader_ptr to
	base_rtx_reader_ptr.
	(unread_char): Likewise.
	* read-rtl.c (rtx_reader_ptr): New global.
	(read_rtx): Use rtx_reader_ptr when calling read_rtx_code.
	(read_rtx_code): Convert to...
	(rtx_reader::read_rtx_code): ...this method.
	(read_rtx_operand): Convert to...
	(rtx_reader::read_rtx_operand): ...this method, eliminating use of
	rtx_reader_ptr singleton.  Convert return type from void to rtx,
	and return input.
	(read_nested_rtx): Convert to...
	(rtx_reader::read_nested_rtx): ...this method.
	(read_rtx_variadic): Convert to...
	(rtx_reader::read_rtx_variadic): ...this method.
	(rtx_reader::rtx_reader): New ctor.
	(rtx_reader::~rtx_reader): New dtor.
---
 gcc/genpreds.c |  6 +++---
 gcc/read-md.c  | 54 ++++++++++++++++++++++++++++--------------------------
 gcc/read-md.h  | 53 +++++++++++++++++++++++++++++++++++++++++++----------
 gcc/read-rtl.c | 48 +++++++++++++++++++++++++++++++++---------------
 4 files changed, 107 insertions(+), 54 deletions(-)

diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index 6db1b7b..a9092da 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -1205,7 +1205,7 @@ write_tm_constrs_h (void)
   printf ("\
 /* Generated automatically by the program '%s'\n\
    from the machine description file '%s'.  */\n\n", progname,
-	  rtx_reader_ptr->get_top_level_filename ());
+	  base_rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_CONSTRS_H\n\
@@ -1405,7 +1405,7 @@ write_tm_preds_h (void)
   printf ("\
 /* Generated automatically by the program '%s'\n\
    from the machine description file '%s'.  */\n\n", progname,
-	  rtx_reader_ptr->get_top_level_filename ());
+	  base_rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_PREDS_H\n\
@@ -1555,7 +1555,7 @@ write_insn_preds_c (void)
   printf ("\
 /* Generated automatically by the program '%s'\n\
    from the machine description file '%s'.  */\n\n", progname,
-	  rtx_reader_ptr->get_top_level_filename ());
+	  base_rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #include \"config.h\"\n\
diff --git a/gcc/read-md.c b/gcc/read-md.c
index 1bbf408..9ffdb8e 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -56,7 +56,7 @@ void (*include_callback) (const char *);
 
 /* Global singleton.  */
 
-rtx_reader *rtx_reader_ptr;
+base_rtx_reader *base_rtx_reader_ptr;
 
 /* A table of md_constant structures, hashed by name.  Null if no
    constant expansion should occur.  */
@@ -274,8 +274,9 @@ fatal_with_file_and_line (const char *msg, ...)
 
   va_start (ap, msg);
 
-  fprintf (stderr, "%s:%d:%d: error: ", rtx_reader_ptr->get_filename (),
-	   rtx_reader_ptr->get_lineno (), rtx_reader_ptr->get_colno ());
+  fprintf (stderr, "%s:%d:%d: error: ", base_rtx_reader_ptr->get_filename (),
+	   base_rtx_reader_ptr->get_lineno (),
+	   base_rtx_reader_ptr->get_colno ());
   vfprintf (stderr, msg, ap);
   putc ('\n', stderr);
 
@@ -295,8 +296,9 @@ fatal_with_file_and_line (const char *msg, ...)
   context[i] = '\0';
 
   fprintf (stderr, "%s:%d:%d: note: following context is `%s'\n",
-	   rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
-	   rtx_reader_ptr->get_colno (), context);
+	   base_rtx_reader_ptr->get_filename (),
+	   base_rtx_reader_ptr->get_lineno (),
+	   base_rtx_reader_ptr->get_colno (), context);
 
   va_end (ap);
   exit (1);
@@ -399,7 +401,7 @@ void require_word_ws (const char *expected)
 /* Read the next character from the file.  */
 
 int
-rtx_reader::read_char (void)
+base_rtx_reader::read_char (void)
 {
   int ch;
 
@@ -419,7 +421,7 @@ rtx_reader::read_char (void)
 /* Put back CH, which was the last character read from the file.  */
 
 void
-rtx_reader::unread_char (int ch)
+base_rtx_reader::unread_char (int ch)
 {
   if (ch == '\n')
     {
@@ -551,8 +553,8 @@ read_escape (void)
       /* pass anything else through, but issue a warning.  */
     default:
       fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
-	       rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
-	       c);
+	       base_rtx_reader_ptr->get_filename (),
+	       base_rtx_reader_ptr->get_lineno (), c);
       obstack_1grow (&string_obstack, '\\');
       break;
     }
@@ -595,7 +597,7 @@ read_braced_string (void)
 {
   int c;
   int brace_depth = 1;  /* caller-processed */
-  unsigned long starting_read_md_lineno = rtx_reader_ptr->get_lineno ();
+  unsigned long starting_read_md_lineno = base_rtx_reader_ptr->get_lineno ();
 
   obstack_1grow (&string_obstack, '{');
   while (brace_depth)
@@ -641,7 +643,7 @@ read_string (int star_if_braced)
       c = read_skip_spaces ();
     }
 
-  old_lineno = rtx_reader_ptr->get_lineno ();
+  old_lineno = base_rtx_reader_ptr->get_lineno ();
   if (c == '"')
     stringbuf = read_quoted_string ();
   else if (c == '{')
@@ -656,7 +658,7 @@ read_string (int star_if_braced)
   if (saw_paren)
     require_char_ws (')');
 
-  set_md_ptr_loc (stringbuf, rtx_reader_ptr->get_filename (), old_lineno);
+  set_md_ptr_loc (stringbuf, base_rtx_reader_ptr->get_filename (), old_lineno);
   return stringbuf;
 }
 
@@ -942,9 +944,9 @@ traverse_enum_types (htab_trav callback, void *info)
 }
 
 
-/* Constructor for rtx_reader.  */
+/* Constructor for base_rtx_reader.  */
 
-rtx_reader::rtx_reader ()
+base_rtx_reader::base_rtx_reader ()
 : m_toplevel_fname (NULL),
   m_base_dir (NULL),
   m_read_md_file (NULL),
@@ -955,7 +957,7 @@ rtx_reader::rtx_reader ()
   m_last_dir_md_include_ptr (&m_first_dir_md_include)
 {
   /* Set the global singleton pointer.  */
-  rtx_reader_ptr = this;
+  base_rtx_reader_ptr = this;
 
   /* Initialize global data.  */
   obstack_init (&string_obstack);
@@ -972,9 +974,9 @@ rtx_reader::rtx_reader ()
   unlock_std_streams ();
 }
 
-/* rtx_reader's destructor.  */
+/* base_rtx_reader's destructor.  */
 
-rtx_reader::~rtx_reader ()
+base_rtx_reader::~base_rtx_reader ()
 {
   free (m_base_dir);
 
@@ -998,7 +1000,7 @@ rtx_reader::~rtx_reader ()
   obstack_free (&string_obstack, NULL);
 
   /* Clear the global singleton pointer.  */
-  rtx_reader_ptr = NULL;
+  base_rtx_reader_ptr = NULL;
 }
 
 /* Process an "include" directive, starting with the optional space
@@ -1007,7 +1009,7 @@ rtx_reader::~rtx_reader ()
    which the "include" occurred.  */
 
 void
-rtx_reader::handle_include (file_location loc)
+base_rtx_reader::handle_include (file_location loc)
 {
   const char *filename;
   const char *old_filename;
@@ -1085,7 +1087,7 @@ rtx_reader::handle_include (file_location loc)
    unknown directives.  */
 
 void
-rtx_reader::handle_file ()
+base_rtx_reader::handle_file ()
 {
   struct md_name directive;
   int c;
@@ -1119,7 +1121,7 @@ rtx_reader::handle_file ()
    and m_base_dir accordingly.  */
 
 void
-rtx_reader::handle_toplevel_file ()
+base_rtx_reader::handle_toplevel_file ()
 {
   const char *base;
 
@@ -1134,7 +1136,7 @@ rtx_reader::handle_toplevel_file ()
 }
 
 file_location
-rtx_reader::get_current_location () const
+base_rtx_reader::get_current_location () const
 {
   return file_location (m_read_md_filename, m_read_md_lineno, m_read_md_colno);
 }
@@ -1142,7 +1144,7 @@ rtx_reader::get_current_location () const
 /* Parse a -I option with argument ARG.  */
 
 void
-rtx_reader::add_include_path (const char *arg)
+base_rtx_reader::add_include_path (const char *arg)
 {
   struct file_name_list *dirtmp;
 
@@ -1163,8 +1165,8 @@ rtx_reader::add_include_path (const char *arg)
    generic error should be reported.  */
 
 bool
-rtx_reader::read_md_files (int argc, const char **argv,
-			   bool (*parse_opt) (const char *))
+base_rtx_reader::read_md_files (int argc, const char **argv,
+				bool (*parse_opt) (const char *))
 {
   int i;
   bool no_more_options;
@@ -1259,7 +1261,7 @@ rtx_reader::read_md_files (int argc, const char **argv,
   return !have_error;
 }
 
-/* class noop_reader : public rtx_reader */
+/* class noop_reader : public base_rtx_reader */
 
 /* A dummy implementation which skips unknown directives.  */
 void
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 88d2d4f..0701f35 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -91,11 +91,23 @@ struct enum_type {
   unsigned int num_values;
 };
 
-class rtx_reader
+/* A class for reading .md files and RTL dump files.
+
+   Implemented in read-md.c.
+
+   This class has responsibility for reading chars from input files, and
+   for certain common top-level directives including the "include"
+   directive.
+
+   It does not handle parsing the hierarchically-nested expressions of
+   rtl.def; for that see the rtx_reader subclass below (implemented in
+   read-rtl.c).  */
+
+class base_rtx_reader
 {
  public:
-  rtx_reader ();
-  virtual ~rtx_reader ();
+  base_rtx_reader ();
+  virtual ~base_rtx_reader ();
 
   bool read_md_files (int, const char **, bool (*) (const char *));
 
@@ -161,20 +173,41 @@ class rtx_reader
   file_name_list **m_last_dir_md_include_ptr;
 };
 
-/* Global singleton.  */
-extern rtx_reader *rtx_reader_ptr;
+/* Global singleton; constrast with rtx_reader_ptr below.  */
+extern base_rtx_reader *base_rtx_reader_ptr;
 
-/* An rtx_reader subclass which skips unknown directives.  */
+/* A base_rtx_reader subclass which skips unknown directives, for
+   the gen* tools that purely use read-md.o.  */
 
-class noop_reader : public rtx_reader
+class noop_reader : public base_rtx_reader
 {
  public:
-  noop_reader () : rtx_reader () {}
+  noop_reader () : base_rtx_reader () {}
 
   /* A dummy implementation which skips unknown directives.  */
   void handle_unknown_directive (file_location, const char *);
 };
 
+/* A base_rtx_reader subclass that actually handles full hierarchical
+   rtx expressions.
+
+   Implemented in read-rtl.c.  */
+
+class rtx_reader : public base_rtx_reader
+{
+ public:
+  rtx_reader ();
+  ~rtx_reader ();
+
+  rtx read_rtx_code (const char *);
+  rtx read_rtx_operand (rtx return_rtx, int idx);
+  rtx read_nested_rtx (void);
+  rtx read_rtx_variadic (rtx);
+};
+
+/* Global singleton; constrast with base_rtx_reader_ptr above.  */
+extern rtx_reader *rtx_reader_ptr;
+
 extern struct obstack string_obstack;
 extern void (*include_callback) (const char *);
 
@@ -183,7 +216,7 @@ extern void (*include_callback) (const char *);
 static inline int
 read_char (void)
 {
-  return rtx_reader_ptr->read_char ();
+  return base_rtx_reader_ptr->read_char ();
 }
 
 /* Put back CH, which was the last character read from the MD file.  */
@@ -191,7 +224,7 @@ read_char (void)
 static inline void
 unread_char (int ch)
 {
-  rtx_reader_ptr->unread_char (ch);
+  base_rtx_reader_ptr->unread_char (ch);
 }
 
 extern int peek_char (void);
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 925ea45..2622bfe 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -106,10 +106,9 @@ htab_t subst_attr_to_iter_map = NULL;
 const char *current_iterator_name;
 
 static void validate_const_int (const char *);
-static rtx read_rtx_code (const char *);
-static void read_rtx_operand (rtx, int);
-static rtx read_nested_rtx (void);
-static rtx read_rtx_variadic (rtx);
+
+/* Global singleton.  */
+rtx_reader *rtx_reader_ptr = NULL;
 
 /* The mode and code iterator structures.  */
 static struct iterator_group modes, codes, ints, substs;
@@ -1076,7 +1075,7 @@ read_rtx (const char *rtx_name, vec<rtx> *rtxen)
       return true;
     }
 
-  apply_iterators (read_rtx_code (rtx_name), rtxen);
+  apply_iterators (rtx_reader_ptr->read_rtx_code (rtx_name), rtxen);
   iterator_uses.truncate (0);
   attribute_uses.truncate (0);
 
@@ -1087,8 +1086,8 @@ read_rtx (const char *rtx_name, vec<rtx> *rtxen)
    either an rtx code or a code iterator.  Parse the rest of the rtx and
    return it.  */
 
-static rtx
-read_rtx_code (const char *code_name)
+rtx
+rtx_reader::read_rtx_code (const char *code_name)
 {
   RTX_CODE code;
   struct mapping *iterator;
@@ -1200,8 +1199,8 @@ read_rtx_code (const char *code_name)
    based on the corresponding format character within GET_RTX_FORMAT
    for the GET_CODE (RETURN_RTX).  */
 
-static void
-read_rtx_operand (rtx return_rtx, int idx)
+rtx
+rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
 {
   RTX_CODE code = GET_CODE (return_rtx);
   const char *format_ptr = GET_RTX_FORMAT (code);
@@ -1304,7 +1303,7 @@ read_rtx_operand (rtx return_rtx, int idx)
 		|| GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
 	  {
 	    char line_name[20];
-	    const char *read_md_filename = rtx_reader_ptr->get_filename ();
+	    const char *read_md_filename = get_filename ();
 	    const char *fn = (read_md_filename ? read_md_filename : "rtx");
 	    const char *slash;
 	    for (slash = fn; *slash; slash ++)
@@ -1312,7 +1311,7 @@ read_rtx_operand (rtx return_rtx, int idx)
 		fn = slash + 1;
 	    obstack_1grow (&string_obstack, '*');
 	    obstack_grow (&string_obstack, fn, strlen (fn));
-	    sprintf (line_name, ":%d", rtx_reader_ptr->get_lineno ());
+	    sprintf (line_name, ":%d", get_lineno ());
 	    obstack_grow (&string_obstack, line_name, strlen (line_name)+1);
 	    stringbuf = XOBFINISH (&string_obstack, char *);
 	  }
@@ -1398,12 +1397,14 @@ read_rtx_operand (rtx return_rtx, int idx)
     default:
       gcc_unreachable ();
     }
+
+  return return_rtx;
 }
 
 /* Read a nested rtx construct from the MD file and return it.  */
 
-static rtx
-read_nested_rtx (void)
+rtx
+rtx_reader::read_nested_rtx (void)
 {
   struct md_name name;
   rtx return_rtx;
@@ -1427,8 +1428,8 @@ read_nested_rtx (void)
    When called, FORM is (thing x1 x2), and the file position
    is just past the leading parenthesis of x3.  Only works
    for THINGs which are dyadic expressions, e.g. AND, IOR.  */
-static rtx
-read_rtx_variadic (rtx form)
+rtx
+rtx_reader::read_rtx_variadic (rtx form)
 {
   char c = '(';
   rtx p = form, q;
@@ -1451,3 +1452,20 @@ read_rtx_variadic (rtx form)
   unread_char (c);
   return form;
 }
+
+/* Constructor for class rtx_reader.  */
+
+rtx_reader::rtx_reader ()
+: base_rtx_reader ()
+{
+  /* Set the global singleton pointer.  */
+  rtx_reader_ptr = this;
+}
+
+/* Destructor for class rtx_reader.  */
+
+rtx_reader::~rtx_reader ()
+{
+  /* Clear the global singleton pointer.  */
+  rtx_reader_ptr = NULL;
+}
-- 
1.8.5.3

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

* [PATCH 16/16] Add "__RTL" to cc1
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (14 preceding siblings ...)
  2016-10-05 15:45 ` [PATCH 04/16] (approved) Expose forcibly_ggc_collect and run it after all selftests David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-05 16:10   ` Joseph Myers
  15 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

This patch implements Richi's idea of having a custom __RTL marker
in C function definitions, to indicate that the body of the function
is to be parsed as RTL, rather than C:

int __RTL test_fn_1 (int i)
{
 (function "times_two"
   (insn-chain
     (note 1 0 4 (nil) NOTE_INSN_DELETED)
     ;; etc
   ) ;; insn-chain
   (crtl
     (return_rtx
       (reg/i:SI 0 ax)
     ) ;; return_rtx
   ) ;; crtl
  ) ;; function
}

This allows for decls and types to be declared in C, and to use
the function decl from the C frontend.

I added support for running a single pass by giving __RTL an optional
parameter (the name of the pass).  For example:

int __RTL ("rtl-dfinit") test_fn_2 (int i)
{
 (function "times_two"
   (insn-chain
     (note 1 0 4 (nil) NOTE_INSN_DELETED)
     ;; etc
   ) ;; insn-chain
   (crtl
     (return_rtx
       (reg/i:SI 0 ax)
     ) ;; return_rtx
   ) ;; crtl
  ) ;; function
}

The top-level "function" directive is rather redundant; perhaps it should
be omitted?  This would give e.g.:

int __RTL ("rtl-dfinit") test_fn_3 (int i)
{
   (insn-chain
     (note 1 0 4 (nil) NOTE_INSN_DELETED)
     ;; etc
   ) ;; insn-chain
   (crtl
     (return_rtx
       (reg/i:SI 0 ax)
     ) ;; return_rtx
   ) ;; crtl
}

(Though maybe we want to keep it as a place to hold top-level metadata)

gcc/c-family/ChangeLog:
	* c-common.c (c_common_reswords): Add "__RTL".
	* c-common.h (enum rid): Add RID_RTL.

gcc/c/ChangeLog:
	* c-parser.c: Include "read-rtl-function.h" and
	"run-one-rtl-pass.h".
	(c_parser_declaration_or_fndef): Handle "__RID" by calling
	c_parser_parse_rtl_body.  Convert a timevar_push/pop pair
	to an auto_timevar, to cope with early exit.
	(c_parser_parse_rtl_body): New function.

gcc/ChangeLog:
	* read-md.c (base_rtx_reader::read_char): Support filtering
	the input to a subset of line numbers.
	(base_rtx_reader::base_rtx_reader): Initialize fields
	m_first_line and m_last_line.
	(base_rtx_reader::read_file_fragment): New method.
	* read-md.h (base_rtx_reader::read_file_fragment): New decl.
	(base_rtx_reader::m_first_line): New field.
	(base_rtx_reader::m_last_line): New field.
	* read-rtl-function.c (function_reader::create_function): Only create
	cfun if it doesn't already exist.
	(read_rtl_function_body_from_file_range): New function.
	* read-rtl-function.h (read_rtl_function_body_from_file_range):
	New decl.

gcc/testsuite/ChangeLog:
	* rtl.dg/rtl.exp: Add .c files below rtl.dg to "tests".
	* rtl.dg/x86_64/different-structs.c: New file.
	* rtl.dg/x86_64/test-return-const.c.after-expand.c: New file.
	* rtl.dg/x86_64/test-return-const.c.before-fwprop.c: New file.
	* rtl.dg/x86_64/test-rtl.c: New file.
	* rtl.dg/x86_64/times-two.c.after-expand.c: New file.
	* rtl.dg/x86_64/times-two.c.before-df.c: New file.
---
 gcc/c-family/c-common.c                            |   1 +
 gcc/c-family/c-common.h                            |   3 +
 gcc/c/c-parser.c                                   | 102 ++++++++++++++++++++-
 gcc/read-md.c                                      |  34 ++++++-
 gcc/read-md.h                                      |   7 ++
 gcc/read-rtl-function.c                            |  78 ++++++++++++----
 gcc/read-rtl-function.h                            |   3 +
 gcc/testsuite/rtl.dg/rtl.exp                       |   4 +-
 gcc/testsuite/rtl.dg/x86_64/different-structs.c    | 101 ++++++++++++++++++++
 .../x86_64/test-return-const.c.after-expand.c      |  23 +++++
 .../x86_64/test-return-const.c.before-fwprop.c     |  27 ++++++
 gcc/testsuite/rtl.dg/x86_64/test-rtl.c             |  95 +++++++++++++++++++
 .../rtl.dg/x86_64/times-two.c.after-expand.c       |  40 ++++++++
 .../rtl.dg/x86_64/times-two.c.before-df.c          |  57 ++++++++++++
 14 files changed, 554 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/different-structs.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-rtl.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 491c637..ecef32b 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -524,6 +524,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
   { "__volatile",	RID_VOLATILE,	0 },
   { "__volatile__",	RID_VOLATILE,	0 },
+  { "__RTL",		RID_RTL,	0 },
   { "alignas",		RID_ALIGNAS,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "alignof",		RID_ALIGNOF,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "asm",		RID_ASM,	D_ASM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index c88619b..e19751e 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -118,6 +118,9 @@ enum rid
 
   RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
 
+  /* "__RTL", for the RTL-parsing extension to the C frontend.  */
+  RID_RTL,
+
   /* C11 */
   RID_ALIGNAS, RID_GENERIC,
 
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 6bc42da..b4993d0 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -59,6 +59,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-expr.h"
 #include "context.h"
 #include "gcc-rich-location.h"
+#include "read-rtl-function.h"
+#include "run-one-rtl-pass.h"
 
 /* We need to walk over decls with incomplete struct/union/enum types
    after parsing the whole translation unit.
@@ -1421,6 +1423,9 @@ static tree c_parser_array_notation (location_t, c_parser *, tree, tree);
 static tree c_parser_cilk_clause_vectorlength (c_parser *, tree, bool);
 static void c_parser_cilk_grainsize (c_parser *, bool *);
 
+static void c_parser_parse_rtl_body (c_parser *parser,
+				     const char *single_pass_name);
+
 /* Parse a translation unit (C90 6.7, C99 6.9).
 
    translation-unit:
@@ -1668,6 +1673,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
   tree all_prefix_attrs;
   bool diagnosed_no_specs = false;
   location_t here = c_parser_peek_token (parser)->location;
+  bool rtl_body_p = false;
+  const char *single_pass_name = NULL;
 
   if (static_assert_ok
       && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
@@ -1752,6 +1759,35 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       c_parser_skip_to_end_of_block_or_statement (parser);
       return;
     }
+
+  if (c_parser_next_token_is (parser, CPP_KEYWORD))
+    {
+      c_token *kw_token = c_parser_peek_token (parser);
+      if (kw_token->keyword == RID_RTL)
+	{
+	  rtl_body_p = true;
+	  c_parser_consume_token (parser);
+	  /* Optionally, parens wrapping a string giving a pass
+	     name.  */
+	  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+	    {
+	      c_parser_consume_token (parser);
+	      c_token *tok = c_parser_peek_token (parser);
+	      if (tok->type != CPP_STRING)
+		{
+		  c_parser_error (parser, "expected string");
+		  c_parser_skip_to_end_of_block_or_statement (parser);
+		  return;
+		}
+	      gcc_assert (TREE_CODE (tok->value) == STRING_CST);
+	      single_pass_name = TREE_STRING_POINTER (tok->value);
+	      c_parser_consume_token (parser);
+
+	      c_parser_require (parser, CPP_CLOSE_PAREN, "FIXME");
+	    }
+	}
+    }
+
   finish_declspecs (specs);
   bool auto_type_p = specs->typespec_word == cts_auto_type;
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
@@ -2146,7 +2182,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
         tv = TV_PARSE_INLINE;
       else
         tv = TV_PARSE_FUNC;
-      timevar_push (tv);
+      auto_timevar at (g_timer, tv);
 
       /* Parse old-style parameter declarations.  ??? Attributes are
 	 not allowed to start declaration specifiers here because of a
@@ -2173,6 +2209,12 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
 	= c_parser_peek_token (parser)->location;
+      if (rtl_body_p)
+	{
+	  c_parser_parse_rtl_body (parser, single_pass_name);
+	  return;
+	}
+
       fnbody = c_parser_compound_statement (parser);
       if (flag_cilkplus && contains_array_notation_expr (fnbody))
 	fnbody = expand_array_notation_exprs (fnbody);
@@ -2195,7 +2237,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	  finish_function ();
 	}
 
-      timevar_pop (tv);
       break;
     }
 }
@@ -18313,4 +18354,61 @@ c_parser_array_notation (location_t loc, c_parser *parser, tree initial_index,
   return value_tree;
 }
 
+/* Parse the body of a function declaration marked with "__RTL".
+
+   The RTL parser works on the level of characters read from a
+   FILE *, whereas c_parser works at the level of tokens.
+   Square this circle by consuming all of the tokens,
+   recording the start/end of the RTL
+   fragment, and reopening the file and re-reading the relevant
+   lines within the RTL parser.  */
+
+void
+c_parser_parse_rtl_body (c_parser *parser, const char *single_pass_name)
+{
+  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    return;
+
+  location_t start_loc = c_parser_peek_token (parser)->location;
+  if (0)
+    inform (start_loc, "start of RTL");
+
+  /* Consume all tokens, up to the closing brace, handling matching
+     pairs of braces in the rtl dump.  */
+  int num_open_braces = 1;
+  while (1)
+    {
+      switch (c_parser_peek_token (parser)->type)
+	{
+	case CPP_OPEN_BRACE:
+	  num_open_braces++;
+	  break;
+	case CPP_CLOSE_BRACE:
+	  if (--num_open_braces == 0)
+	    goto found_closing_brace;
+	  break;
+	default:
+	  break;
+	}
+      c_parser_consume_token (parser);
+    }
+
+ found_closing_brace:
+  /* At the closing brace; record its location.  */
+  location_t end_loc = c_parser_peek_token (parser)->location;
+  if (0)
+    inform (end_loc, "end of RTL");
+
+  /* Consume the closing brace.  */
+  c_parser_consume_token (parser);
+
+  if (!read_rtl_function_body_from_file_range (start_loc, end_loc))
+    return;
+
+ /*  If -fsingle-pass=PASS_NAME was provided, locate and run PASS_NAME
+      on cfun, as created above.  */
+  if (single_pass_name)
+    run_one_rtl_pass_by_name (single_pass_name);
+}
+
 #include "gt-c-c-parser.h"
diff --git a/gcc/read-md.c b/gcc/read-md.c
index b6bafe7..daa4e1c 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -417,6 +417,16 @@ base_rtx_reader::read_char (void)
   else
     m_read_md_colno++;
 
+  /* If we're filtering lines, treat everything outside the
+     range of interest as a space.  */
+  if (m_first_line && m_last_line)
+    {
+      if (m_read_md_lineno < m_first_line)
+	return ' ';
+      if (m_read_md_lineno > m_last_line)
+	return EOF;
+    }
+
   return ch;
 }
 
@@ -998,7 +1008,9 @@ base_rtx_reader::base_rtx_reader ()
   m_read_md_lineno (0),
   m_read_md_colno (0),
   m_first_dir_md_include (NULL),
-  m_last_dir_md_include_ptr (&m_first_dir_md_include)
+  m_last_dir_md_include_ptr (&m_first_dir_md_include),
+  m_first_line (0),
+  m_last_line (0)
 {
   /* Set the global singleton pointer.  */
   base_rtx_reader_ptr = this;
@@ -1305,6 +1317,26 @@ base_rtx_reader::read_md_files (int argc, const char **argv,
   return !have_error;
 }
 
+/* Read FILENAME, filtering to just the given lines.  */
+
+bool
+base_rtx_reader::read_file_fragment (const char *filename,
+				     int first_line,
+				     int last_line)
+{
+  m_read_md_filename = filename;
+  m_read_md_file = fopen (m_read_md_filename, "r");
+  if (m_read_md_file == 0)
+    {
+      perror (m_read_md_filename);
+      return false;
+    }
+  m_first_line = first_line;
+  m_last_line = last_line;
+  handle_toplevel_file ();
+  return !have_error;
+}
+
 /* class noop_reader : public base_rtx_reader */
 
 /* A dummy implementation which skips unknown directives.  */
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 4933912..2058002 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -98,6 +98,9 @@ class base_rtx_reader
   virtual ~base_rtx_reader ();
 
   bool read_md_files (int, const char **, bool (*) (const char *));
+  bool read_file_fragment (const char *filename,
+			   int first_line,
+			   int last_line);
 
   /* A hook that handles a single .md-file directive, up to but not
      including the closing ')'.  It takes two arguments: the file position
@@ -159,6 +162,10 @@ class base_rtx_reader
 
   /* A pointer to the null terminator of the md include chain.  */
   file_name_list **m_last_dir_md_include_ptr;
+
+  /* If non-zero, filter the input to just this subset of lines.  */
+  int m_first_line;
+  int m_last_line;
 };
 
 /* Global singleton; constrast with rtx_reader_ptr below.  */
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
index 0723585..73493ec 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -593,23 +593,31 @@ function_reader::create_function ()
   else
     rtl_register_cfg_hooks ();
 
-  /* Create cfun.  */
-  tree fn_name = get_identifier (m_name ? m_name : "test_1");
-  tree int_type = integer_type_node;
-  tree return_type = int_type;
-  tree arg_types[3] = {int_type, int_type, int_type};
-  tree fn_type = build_function_type_array (return_type, 3, arg_types);
-  tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
-				 fn_type);
-  tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
-			     return_type);
-  DECL_ARTIFICIAL (resdecl) = 1;
-  DECL_IGNORED_P (resdecl) = 1;
-  DECL_RESULT (fndecl) = resdecl;
-  allocate_struct_function (fndecl, false);
-  /* This sets cfun.  */
-
-  current_function_decl = fndecl;
+  /* When run from selftests or "rtl1", cfun is NULL.
+     When run from "cc1" for a C function tagged with __RTL, cfun is the
+     tagged function.  */
+  if (!cfun)
+    {
+      tree fn_name = get_identifier (m_name ? m_name : "test_1");
+      tree int_type = integer_type_node;
+      tree return_type = int_type;
+      tree arg_types[3] = {int_type, int_type, int_type};
+      tree fn_type = build_function_type_array (return_type, 3, arg_types);
+      tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+				     fn_type);
+      tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+				 return_type);
+      DECL_ARTIFICIAL (resdecl) = 1;
+      DECL_IGNORED_P (resdecl) = 1;
+      DECL_RESULT (fndecl) = resdecl;
+      allocate_struct_function (fndecl, false);
+      /* This sets cfun.  */
+      current_function_decl = fndecl;
+    }
+
+  gcc_assert (cfun);
+  gcc_assert (current_function_decl);
+  tree fndecl = current_function_decl;
 
   cfun->curr_properties = (PROP_cfg | PROP_rtl);
 
@@ -1817,6 +1825,42 @@ read_rtl_function_body (int argc, const char **argv,
   return true;
 }
 
+/* Run the RTL dump parser on the range of lines between START_LOC and
+   END_LOC (including those lines).  */
+
+bool
+read_rtl_function_body_from_file_range (location_t start_loc,
+					location_t end_loc)
+{
+  expanded_location exploc_start = expand_location (start_loc);
+  expanded_location exploc_end = expand_location (end_loc);
+
+  if (exploc_start.file != exploc_end.file)
+    {
+      error_at (end_loc, "start/end of RTL fragment are in different files");
+      return false;
+    }
+  if (exploc_start.line >= exploc_end.line)
+    {
+      error_at (end_loc,
+		"start of RTL fragment must be on an earlier line than end");
+      return false;
+    }
+
+  in_rtl_frontend_p = true;
+
+  initialize_rtl ();
+  init_emit ();
+  init_varasm_status ();
+
+  function_reader reader (NULL);
+  if (!reader.read_file_fragment (exploc_start.file, exploc_start.line,
+				  exploc_end.line - 1))
+    return false;
+
+  return true;
+}
+
 #if CHECKING_P
 
 namespace selftest {
diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
index d26c797..c69d308 100644
--- a/gcc/read-rtl-function.h
+++ b/gcc/read-rtl-function.h
@@ -34,4 +34,7 @@ extern bool read_rtl_function_body (int argc, const char **argv,
 				    function_reader_policy *policy,
 				    int *out_pseudo_offset);
 
+extern bool read_rtl_function_body_from_file_range (location_t start_loc,
+						    location_t end_loc);
+
 #endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/testsuite/rtl.dg/rtl.exp b/gcc/testsuite/rtl.dg/rtl.exp
index 71bebb9..6c7c7f4 100644
--- a/gcc/testsuite/rtl.dg/rtl.exp
+++ b/gcc/testsuite/rtl.dg/rtl.exp
@@ -29,8 +29,10 @@ if ![info exists DEFAULT_RTLFLAGS] then {
 # Initialize `dg'.
 dg-init
 
-# Gather a list of all tests.
+# Gather a list of all tests: both .rtl tests for use with rtl1, and .c tests
+# for use with cc1.
 set tests [lsort [find $srcdir/$subdir *.rtl]]
+set tests [concat $tests [lsort [find $srcdir/$subdir *.c]]]
 
 verbose "rtl.exp tests: $tests" 1
 
diff --git a/gcc/testsuite/rtl.dg/x86_64/different-structs.c b/gcc/testsuite/rtl.dg/x86_64/different-structs.c
new file mode 100644
index 0000000..d5c0bed
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/different-structs.c
@@ -0,0 +1,101 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+extern double sqrt(double x);
+
+struct foo
+{
+  double x;
+  double y;
+};
+
+struct bar
+{
+  double x;
+  double y;
+};
+
+double __RTL test (struct foo *f, const struct bar *b)
+{
+#if 0
+  /* Result of "expand" on this C code, compiled for x86_64 with -Os.  */
+  f->x += b->x;
+  f->y += b->y;
+  return sqrt (f->x * f->x + f->y * f->y);
+#endif
+(function "test"
+  (insn-chain
+    (note 1 0 5 (nil) NOTE_INSN_DELETED)
+    (note 5 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+    (insn 2 5 3 2 (set (reg/v/f:DI 97 [ f ])
+                (reg:DI 5 di [ f ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:16 -1
+             (nil))
+    (insn 3 2 4 2 (set (reg/v/f:DI 98 [ b ])
+                (reg:DI 4 si [ b ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:16 -1
+             (nil))
+    (note 4 3 7 2 NOTE_INSN_FUNCTION_BEG)
+    (insn 7 4 8 2 (set (reg:DF 99)
+                (mem:DF (reg/v/f:DI 97 [ f ]) [2 f_11(D)->x+0 S8 A64])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
+             (nil))
+    (insn 8 7 9 2 (set (reg:DF 89 [ _3 ])
+                (plus:DF (reg:DF 99)
+                    (mem:DF (reg/v/f:DI 98 [ b ]) [2 b_12(D)->x+0 S8 A64]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
+             (nil))
+    (insn 9 8 10 2 (set (mem:DF (reg/v/f:DI 97 [ f ]) [2 f_11(D)->x+0 S8 A64])
+                (reg:DF 89 [ _3 ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
+             (nil))
+    (insn 10 9 11 2 (set (reg:DF 100)
+                (mem:DF (plus:DI (reg/v/f:DI 97 [ f ])
+                        (const_int 8 [0x8])) [2 f_11(D)->y+0 S8 A64])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
+             (nil))
+    (insn 11 10 12 2 (set (reg:DF 92 [ _6 ])
+                (plus:DF (reg:DF 100)
+                    (mem:DF (plus:DI (reg/v/f:DI 98 [ b ])
+                            (const_int 8 [0x8])) [2 b_12(D)->y+0 S8 A64]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
+             (nil))
+    (insn 12 11 13 2 (set (mem:DF (plus:DI (reg/v/f:DI 97 [ f ])
+                        (const_int 8 [0x8])) [2 f_11(D)->y+0 S8 A64])
+                (reg:DF 92 [ _6 ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
+             (nil))
+    (insn 13 12 14 2 (set (reg:DF 101)
+                (mult:DF (reg:DF 89 [ _3 ])
+                    (reg:DF 89 [ _3 ]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (insn 14 13 15 2 (set (reg:DF 102)
+                (mult:DF (reg:DF 92 [ _6 ])
+                    (reg:DF 92 [ _6 ]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (insn 15 14 16 2 (set (reg:DF 103)
+                (plus:DF (reg:DF 101)
+                    (reg:DF 102))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (insn 16 15 17 2 (set (reg:DF 21 xmm0)
+                (reg:DF 103)) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (call_insn/j 17 16 18 2 (set (reg:DF 21 xmm0)
+                (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
+                    (const_int 0 [0]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>)
+                (expr_list:REG_EH_REGION (const_int 0 [0])
+                    (nil)))
+            (expr_list:DF (use (reg:DF 21 xmm0))
+                (nil)))
+    (barrier 18 17 0)
+  ) ;; insn-chain
+  (cfg
+    (bb 0
+      (edge 0 2 (flags 0x1))
+    ) ;; bb
+    (bb 2
+      (edge 2 1 (flags 0x1002))
+    ) ;; bb
+    (bb 1
+    ) ;; bb
+  ) ;; cfg
+  (crtl
+    (return_rtx 
+      (reg/i:DF 21 xmm0)
+    ) ;; return_rtx
+  ) ;; crtl
+) ;; function "test"
+
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
new file mode 100644
index 0000000..11b6f24
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
@@ -0,0 +1,23 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+int __RTL test_returning_constant (void)
+{
+  /* C code:
+     return 42; */
+
+  (function "test_returning_constant"
+    (insn-chain
+      (note 1 0 3 (nil) NOTE_INSN_DELETED)
+      (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+      (insn 5 2 9 2 (set (reg:SI 87 [ <retval> ])
+	    (const_int 42 [0x2a])) test-return-const.c:3 -1
+         (nil))
+      (insn 9 5 10 2 (set (reg/i:SI 0 ax)
+	      (reg:SI 87 [ <retval> ])) test-return-const.c:4 -1
+         (nil))
+      (insn 10 9 0 2 (use (reg/i:SI 0 ax)) test-return-const.c:4 -1
+         (nil))
+     ) ;; insn-chain
+   );; function
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
new file mode 100644
index 0000000..83594b3
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
@@ -0,0 +1,27 @@
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-fwprop1" } */
+
+int __RTL ("rtl-fwprop1") test_returning_constant (void)
+{
+  /* C code:
+     return 42; */
+  (function "test"
+    (insn-chain
+      (note 3 0 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+      (insn 5 2 9 2 (set (reg:SI 87 [ <retval> ])
+        (const_int 42 [0x2a])) test-return-const.c:3 82 {*movsi_internal}
+        (nil))
+      (insn 9 5 10 2 (set (reg/i:SI 0 ax)
+	(const_int 42 [0x2a])) test-return-const.c:4 82 {*movsi_internal}
+        (expr_list:REG_DEAD (reg:SI 87 [ <retval> ])
+	 (nil)))
+      (insn 10 9 0 2 (use (reg/i:SI 0 ax)) test-return-const.c:4 -1
+       (nil))
+    ) ;; insn-chain
+  ) ;; function
+}
+
+/* Verify that insn 5 is eliminated.  */
+/* { dg-final { scan-rtl-dump "deferring deletion of insn with uid = 5" "fwprop1" } } */
+/* { dg-final { scan-rtl-dump "Deleted 1 trivially dead insns" "fwprop1" } } */
diff --git a/gcc/testsuite/rtl.dg/x86_64/test-rtl.c b/gcc/testsuite/rtl.dg/x86_64/test-rtl.c
new file mode 100644
index 0000000..0ffeab7
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/test-rtl.c
@@ -0,0 +1,95 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+/* Test of embedding RTL dump in a C function, tagged with "__RTL".
+
+   This is a dump of test.c from immediately after "expand", for x86_64.  */
+
+int __RTL test_1 (int i, int j, int k)
+{
+  /*
+    if (i < j)
+      return k + 4;
+    else
+      return -k;
+  */
+  (function "test_1"
+   (insn-chain
+  (note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 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 ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 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])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 4 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 14 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 14 13 15 4 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 15 14 16)
+(code_label 16 15 17 5 2 (nil) [1 uses])
+(note 17 16 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 5 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 5 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 6 3 (nil) [1 uses])
+(note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 6 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 6 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+
+    ) ;; insn-chain
+   ) ;; function
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c b/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
new file mode 100644
index 0000000..8536bf4
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
@@ -0,0 +1,40 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+int __RTL times_two (int i)
+{
+  /* C function:
+     return i * 2;  */
+  (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 ])) times-two.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])) times-two.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))
+        ]) times-two.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 ])) times-two.c:3 -1
+     (nil))
+  (insn 14 10 15 2 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) times-two.c:4 -1
+     (nil))
+  (insn 15 14 0 2 (use (reg/i:SI 0 ax)) times-two.c:4 -1
+     (nil))
+    ) ;; insn-chain
+  ) ;; function
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c b/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
new file mode 100644
index 0000000..b4d20a7
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
@@ -0,0 +1,57 @@
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-dfinit" } */
+
+int __RTL ("rtl-dfinit") times_two (int i)
+{
+  /* C function:
+     return i * 2;  */
+ (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 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) times-two.c:2 82 {*movsi_internal}
+     (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 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) times-two.c:3 82 {*movsi_internal}
+     (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))
+        ]) times-two.c:3 529 {*ashlsi3_1}
+     (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (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 ])) times-two.c:3 82 {*movsi_internal}
+     (nil))
+   (insn 14 10 15 2 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) times-two.c:4 82 {*movsi_internal}
+     (nil))
+   (insn 15 14 0 2 (use (reg/i:SI 0 ax)) times-two.c:4 -1
+     (nil))
+   ) ;; insn-chain
+
+   (crtl
+     (return_rtx
+       (reg/i:SI 0 ax)
+     ) ;; return_rtx
+   ) ;; crtl
+  ) ;; function
+}
+
+/* Verify that the dataflow information matches what cc1 would have
+   generated.  In particular, in earlier versions of the RTL
+   frontend, the exit block use of reg 0 (ax) wasn't picked up
+   on, due to not setting up crtl->return_rtx based on
+   DECL_RESULT (fndecl).  */
+
+/* { dg-final { scan-rtl-dump ";;  exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+
+/* { dg-final { scan-rtl-dump ";;  regs ever live.*0 .ax. 5 .di. 17 .flags." "dfinit" } } */
-- 
1.8.5.3

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

* [PATCH 13/16] cse.c selftests
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (4 preceding siblings ...)
  2016-10-05 15:45 ` [PATCH 02/16] (approved) Add selftest::read_file David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-05 15:45 ` [PATCH 12/16] combine.c selftests (v2) David Malcolm
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Changed in v2:
* move test dumps into external files
* update for addition of selftest::location to rtl_dump_test

Blurb from v1:

This patch uses rtl_dump_test to start building out a test suite
for cse.

I attempted to create a reproducer for PR 71779; however I'm not yet
able to replicate the bogus cse reported there via the test case.

gcc/ChangeLog:
	* cse.c: Include selftest.h and selftest-rtl.h.
	(selftest::test_simple_cse): New function.
	(selftest::test_pr71779): New function.
	(selftest::cse_c_tests): New function.
	* selftest-run-tests.c (selftest::run_tests): Call
	selftest::cse_c_tests.
	* selftest.h (selftest::cse_c_tests): New decl.

gcc/testsuite/ChangeLog:
	* selftests/pr71779.rtl: New file.
	* selftests/simple-cse.rtl: New file.
---
 gcc/cse.c                              | 70 ++++++++++++++++++++++++++++++++++
 gcc/selftest-run-tests.c               |  1 +
 gcc/selftest.h                         |  1 +
 gcc/testsuite/selftests/pr71779.rtl    | 39 +++++++++++++++++++
 gcc/testsuite/selftests/simple-cse.rtl | 12 ++++++
 5 files changed, 123 insertions(+)
 create mode 100644 gcc/testsuite/selftests/pr71779.rtl
 create mode 100644 gcc/testsuite/selftests/simple-cse.rtl

diff --git a/gcc/cse.c b/gcc/cse.c
index 7069fab..96beb68 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -41,6 +41,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "dbgcnt.h"
 #include "rtl-iter.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
 
 #ifndef LOAD_EXTEND_OP
 #define LOAD_EXTEND_OP(M) UNKNOWN
@@ -7773,3 +7775,71 @@ make_pass_cse_after_global_opts (gcc::context *ctxt)
 {
   return new pass_cse_after_global_opts (ctxt);
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for CSE.  */
+
+/* Simple test of eliminating a redundant (reg + 1) computation
+   i.e. that:
+     r101 = r100 + 1;
+     r102 = r100 + 1; <<< common subexpression
+     *r103 = r101 * r102;
+   can be CSE-ed to:
+     r101 = r100 + 1;
+     r102 = r101; <<< replaced
+     *r103 = r101 * r102;
+   by cse_main.  */
+
+static void
+test_simple_cse ()
+{
+  /* Only run this tests for i386.  */
+#ifndef I386_OPTS_H
+  return;
+#endif
+
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("simple-cse.rtl"));
+  dataflow_test df_test;
+
+  int tem;
+  tem = cse_main (get_insns (), max_reg_num ());
+  ASSERT_EQ (0, tem);
+
+  /* Verify that insn 2's SET_SRC has been replaced with
+     the SET_DEST of insn 1.  */
+  ASSERT_EQ (SET_DEST (PATTERN (get_insn_by_uid (1))),
+	     SET_SRC (PATTERN (get_insn_by_uid (2))));
+}
+
+/* Towards a regression test for PR 71779.  */
+
+static void
+test_pr71779 ()
+{
+  /* Only run this tests for target==aarch64.  */
+#ifndef GCC_AARCH64_H
+  return;
+#endif
+
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("pr71779.rtl"));
+  dataflow_test df_test;
+
+  int tem;
+  tem = cse_main (get_insns (), max_reg_num ());
+  ASSERT_EQ (0, tem);
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+cse_c_tests ()
+{
+  test_simple_cse ();
+  test_pr71779 ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index a10657f..f110a08 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -72,6 +72,7 @@ selftest::run_tests ()
   rtl_tests_c_tests ();
   read_rtl_function_c_tests ();
   df_core_c_tests ();
+  cse_c_tests ();
 
   /* Higher-level tests, or for components that other selftests don't
      rely on.  */
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 95bf9b2..e07fa26 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -201,6 +201,7 @@ extern const char *path_to_src_gcc;
    alphabetical order.  */
 extern void bitmap_c_tests ();
 extern void combine_c_tests ();
+extern void cse_c_tests ();
 extern void df_core_c_tests ();
 extern void diagnostic_c_tests ();
 extern void diagnostic_show_locus_c_tests ();
diff --git a/gcc/testsuite/selftests/pr71779.rtl b/gcc/testsuite/selftests/pr71779.rtl
new file mode 100644
index 0000000..5c4463f
--- /dev/null
+++ b/gcc/testsuite/selftests/pr71779.rtl
@@ -0,0 +1,39 @@
+;; Dump taken from comment 2 of PR 71779, of
+;; "...the relevant memory access coming out of expand"
+;; with basic block IDs added, and prev/next insns set to
+;; 0 at ends, and 'p' added to pseudo regnos.
+
+(function "fragment"
+  (insn-chain
+
+;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
+(insn 1045 0 1046 2 (set (reg:SI 480)
+        (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
+                    [flags 0xc0]
+                    <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+     y.c:12702 -1
+     (nil))
+(insn 1046 1045 1047 2 (set (reg/f:SI 479)
+        (lo_sum:SI (reg:SI 480)
+            (symbol_ref:SI ("isl_obj_map_vtable")
+               [flags 0xc0]
+               <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+     y.c:12702 -1
+     (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
+                             [flags 0xc0]
+                             <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)
+        (nil)))
+(insn 1047 1046 1048 2 (set (reg:DI 481)
+        (subreg:DI (reg/f:SI 479) 0)) y.c:12702 -1
+     (nil))
+(insn 1048 1047 1049 2 (set (zero_extract:DI (reg/v:DI 191 [ obj1D.17368 ])
+            (const_int 32 [0x20])
+            (const_int 0 [0]))
+        (reg:DI 481)) y.c:12702 -1
+     (nil))
+;; Extra insn, to avoid all of the above from being deleted by DCE
+(insn 1049 1048 0 2 (set (mem:DI (reg:DI 191) [1 i+0 S4 A32])
+                         (const_int 1 [0x1])) -1 (nil))
+
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/simple-cse.rtl b/gcc/testsuite/selftests/simple-cse.rtl
new file mode 100644
index 0000000..ee1c42e
--- /dev/null
+++ b/gcc/testsuite/selftests/simple-cse.rtl
@@ -0,0 +1,12 @@
+(function "test_of_cse"
+  (insn-chain
+    (insn 1 0 2 2 (set (reg:SI 101)
+                       (plus:SI (reg:SI 100)
+                                (const_int 1 [0x1]))) -1 (nil))
+    (insn 2 1 3 2 (set (reg:SI 102)
+                       (plus:SI (reg:SI 100)
+                                (const_int 1 [0x1]))) -1 (nil))
+    (insn 3 2 0 2 (set (mem:SI (reg:SI 103) [1 i+0 S4 A32])
+                               (mult:SI (reg:SI 101) (reg:SI 102))) -1 (nil))
+  ) ;; insn-chain
+) ;; function
-- 
1.8.5.3

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

* [PATCH 05/16] Introduce rtl_data::init_stack_alignment
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (7 preceding siblings ...)
  2016-10-05 15:45 ` [PATCH 10/16] Introduce class function_reader (v3) David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-05 15:52   ` Bernd Schmidt
  2016-10-05 15:45 ` [PATCH 15/16] RTL frontend (rtl1), on top of dump reader David Malcolm
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Move this part of "expand"'s initialization of crtl into its own
method so that it can used by the RTL frontend when postprocessing
RTL dumps.

gcc/ChangeLog:
	* cfgexpand.c (pass_expand::execute): Move stack initializations
	to rtl_data::init_stack_alignment and call it.
	* emit-rtl.c (rtl_data::init_stack_alignment): New method.
	* emit-rtl.h (rtl_data::init_stack_alignment): New method.
---
 gcc/cfgexpand.c |  5 +----
 gcc/emit-rtl.c  | 12 ++++++++++++
 gcc/emit-rtl.h  |  2 ++
 3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 4190f7f..70dfe34 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -6218,10 +6218,7 @@ pass_expand::execute (function *fun)
   discover_nonconstant_array_refs ();
 
   targetm.expand_to_rtl_hook ();
-  crtl->stack_alignment_needed = STACK_BOUNDARY;
-  crtl->max_used_stack_slot_alignment = STACK_BOUNDARY;
-  crtl->stack_alignment_estimated = 0;
-  crtl->preferred_stack_boundary = STACK_BOUNDARY;
+  crtl->init_stack_alignment ();
   fun->cfg->max_jumptable_ents = 0;
 
   /* Resovle the function section.  Some targets, like ARM EABI rely on knowledge
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 2d6d1eb..fdfc790 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -6285,5 +6285,17 @@ need_atomic_barrier_p (enum memmodel model, bool pre)
       gcc_unreachable ();
     }
 }
+
+/* Initialize fields of rtl_data related to stack alignment.  */
+
+void
+rtl_data::init_stack_alignment ()
+{
+  stack_alignment_needed = STACK_BOUNDARY;
+  max_used_stack_slot_alignment = STACK_BOUNDARY;
+  stack_alignment_estimated = 0;
+  preferred_stack_boundary = STACK_BOUNDARY;
+}
+
 \f
 #include "gt-emit-rtl.h"
diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h
index 52c72b1..663b4a0 100644
--- a/gcc/emit-rtl.h
+++ b/gcc/emit-rtl.h
@@ -55,6 +55,8 @@ struct GTY(()) incoming_args {
 
 /* Datastructures maintained for currently processed function in RTL form.  */
 struct GTY(()) rtl_data {
+  void init_stack_alignment ();
+
   struct expr_status expr;
   struct emit_status emit;
   struct varasm_status varasm;
-- 
1.8.5.3

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

* [PATCH 06/16] Introduce emit_status::ensure_regno_capacity
  2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
                   ` (12 preceding siblings ...)
  2016-10-05 15:45 ` [PATCH 03/16] (approved) selftest.h: add temp_override fixture David Malcolm
@ 2016-10-05 15:45 ` David Malcolm
  2016-10-05 15:55   ` Bernd Schmidt
  2016-10-05 15:55   ` [PATCH 06/16] Introduce emit_status::ensure_regno_capacity Bernd Schmidt
  2016-10-05 15:45 ` [PATCH 04/16] (approved) Expose forcibly_ggc_collect and run it after all selftests David Malcolm
  2016-10-05 15:45 ` [PATCH 16/16] Add "__RTL" to cc1 David Malcolm
  15 siblings, 2 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-05 15:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/ChangeLog:
	* emit-rtl.c (gen_reg_rtx): Move regno_pointer_align and
	regno_reg_rtx resizing logic to...
	(emit_status::ensure_regno_capacity): ...this new method.
	(init_emit): Allocate regno_reg_rtx using ggc_cleared_vec_alloc
	rather than ggc_vec_alloc.
	* function.h (emit_status::ensure_regno_capacity): New method.
---
 gcc/emit-rtl.c | 45 ++++++++++++++++++++++++++-------------------
 gcc/function.h |  2 ++
 2 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index fdfc790..12bdbb0 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1056,29 +1056,35 @@ gen_reg_rtx (machine_mode mode)
   /* Do not call gen_reg_rtx with uninitialized crtl.  */
   gcc_assert (crtl->emit.regno_pointer_align_length);
 
-  /* Make sure regno_pointer_align, and regno_reg_rtx are large
-     enough to have an element for this pseudo reg number.  */
+  int cur_size = crtl->emit.regno_pointer_align_length;
+  if (reg_rtx_no == cur_size)
+    crtl->emit.ensure_regno_capacity (cur_size * 2);
 
-  if (reg_rtx_no == crtl->emit.regno_pointer_align_length)
-    {
-      int old_size = crtl->emit.regno_pointer_align_length;
-      char *tmp;
-      rtx *new1;
+  val = gen_raw_REG (mode, reg_rtx_no);
+  regno_reg_rtx[reg_rtx_no++] = val;
+  return val;
+}
+
+/* Make sure m_regno_pointer_align, and regno_reg_rtx are large
+   enough to have elements in the range 0 <= idx < NEW_SIZE.  */
+
+void
+emit_status::ensure_regno_capacity (int new_size)
+{
+  if (new_size < regno_pointer_align_length)
+    return;
 
-      tmp = XRESIZEVEC (char, crtl->emit.regno_pointer_align, old_size * 2);
-      memset (tmp + old_size, 0, old_size);
-      crtl->emit.regno_pointer_align = (unsigned char *) tmp;
+  int old_size = regno_pointer_align_length;
 
-      new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, old_size * 2);
-      memset (new1 + old_size, 0, old_size * sizeof (rtx));
-      regno_reg_rtx = new1;
+  char *tmp = XRESIZEVEC (char, regno_pointer_align, new_size);
+  memset (tmp + old_size, 0, new_size - old_size);
+  regno_pointer_align = (unsigned char *) tmp;
 
-      crtl->emit.regno_pointer_align_length = old_size * 2;
-    }
+  rtx *new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, new_size);
+  memset (new1 + old_size, 0, (new_size - old_size) * sizeof (rtx));
+  regno_reg_rtx = new1;
 
-  val = gen_raw_REG (mode, reg_rtx_no);
-  regno_reg_rtx[reg_rtx_no++] = val;
-  return val;
+  crtl->emit.regno_pointer_align_length = new_size;
 }
 
 /* Return TRUE if REG is a PARM_DECL, FALSE otherwise.  */
@@ -5667,7 +5673,8 @@ init_emit (void)
   crtl->emit.regno_pointer_align
     = XCNEWVEC (unsigned char, crtl->emit.regno_pointer_align_length);
 
-  regno_reg_rtx = ggc_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
+  regno_reg_rtx =
+    ggc_cleared_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
 
   /* Put copies of all the hard registers into regno_reg_rtx.  */
   memcpy (regno_reg_rtx,
diff --git a/gcc/function.h b/gcc/function.h
index 590a490..db9f4ea 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -34,6 +34,8 @@ struct GTY(()) sequence_stack {
 };
 \f
 struct GTY(()) emit_status {
+  void ensure_regno_capacity (int new_size);
+
   /* This is reset to LAST_VIRTUAL_REGISTER + 1 at the start of each function.
      After rtl generation, it is 1 plus the largest register number used.  */
   int x_reg_rtx_no;
-- 
1.8.5.3

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

* Re: [PATCH 01/16] read-md.c: Add various cleanups to ~rtx_reader
  2016-10-05 15:44 ` [PATCH 01/16] read-md.c: Add various cleanups to ~rtx_reader David Malcolm
@ 2016-10-05 15:51   ` Bernd Schmidt
  2016-10-11 15:15     ` David Malcolm
  0 siblings, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-05 15:51 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/05/2016 06:14 PM, David Malcolm wrote:
> The selftests for the RTL frontend require supporting multiple
> reader instances being alive one after another in-process, so
> this lack of cleanup would become a leak.

> +  /* Initialize global data.  */
> +  obstack_init (&string_obstack);
> +  ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
> +  obstack_init (&ptr_loc_obstack);
> +  joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
> +  obstack_init (&joined_conditions_obstack);
> +  md_constants = htab_create (31, leading_string_hash,
> +			      leading_string_eq_p, (htab_del) 0);
> +  enum_types = htab_create (31, leading_string_hash,
> +			    leading_string_eq_p, (htab_del) 0);
> +
> +  /* Unlock the stdio streams.  */
> +  unlock_std_streams ();

Hmm, but these are global statics. Shouldn't they first be moved to 
become class members?


Bernd

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

* Re: [PATCH 05/16] Introduce rtl_data::init_stack_alignment
  2016-10-05 15:45 ` [PATCH 05/16] Introduce rtl_data::init_stack_alignment David Malcolm
@ 2016-10-05 15:52   ` Bernd Schmidt
  0 siblings, 0 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-05 15:52 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/05/2016 06:14 PM, David Malcolm wrote:
> Move this part of "expand"'s initialization of crtl into its own
> method so that it can used by the RTL frontend when postprocessing
> RTL dumps.
>
> gcc/ChangeLog:
> 	* cfgexpand.c (pass_expand::execute): Move stack initializations
> 	to rtl_data::init_stack_alignment and call it.
> 	* emit-rtl.c (rtl_data::init_stack_alignment): New method.
> 	* emit-rtl.h (rtl_data::init_stack_alignment): New method.

Ok.


Bernd

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

* Re: [PATCH 06/16] Introduce emit_status::ensure_regno_capacity
  2016-10-05 15:45 ` [PATCH 06/16] Introduce emit_status::ensure_regno_capacity David Malcolm
@ 2016-10-05 15:55   ` Bernd Schmidt
  2016-11-18 20:47     ` [PATCH] Introduce emit_status::ensure_regno_capacity (v5) David Malcolm
  2016-10-05 15:55   ` [PATCH 06/16] Introduce emit_status::ensure_regno_capacity Bernd Schmidt
  1 sibling, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-05 15:55 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/05/2016 06:15 PM, David Malcolm wrote:
> -  /* Make sure regno_pointer_align, and regno_reg_rtx are large
> -     enough to have an element for this pseudo reg number.  */
> +  int cur_size = crtl->emit.regno_pointer_align_length;
> +  if (reg_rtx_no == cur_size)
> +    crtl->emit.ensure_regno_capacity (cur_size * 2);

Patch looks ok in principle, but maybe this manipulation of the size 
should be part of the new function as well - i.e. don't pass a new_size 
to it, make it check reg_rtx_no itself.


Bernd

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

* Re: [PATCH 06/16] Introduce emit_status::ensure_regno_capacity
  2016-10-05 15:45 ` [PATCH 06/16] Introduce emit_status::ensure_regno_capacity David Malcolm
  2016-10-05 15:55   ` Bernd Schmidt
@ 2016-10-05 15:55   ` Bernd Schmidt
  1 sibling, 0 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-05 15:55 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/05/2016 06:15 PM, David Malcolm wrote:
>
> -  regno_reg_rtx = ggc_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
> +  regno_reg_rtx =
> +    ggc_cleared_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);

Oops, also: formatting, operators go first on a newline.


Bernd

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

* Re: [PATCH 07/16] read-md: add some helper functions
  2016-10-05 15:44 ` [PATCH 07/16] read-md: add some helper functions David Malcolm
@ 2016-10-05 15:57   ` Bernd Schmidt
  0 siblings, 0 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-05 15:57 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/05/2016 06:15 PM, David Malcolm wrote:

> +void require_char (char expected)
 > +void require_word_ws (const char *expected)

Function name goes on a new line. Otherwise ok.


Bernd

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

* Re: [PATCH 10/16] Introduce class function_reader (v3)
  2016-10-05 15:45 ` [PATCH 10/16] Introduce class function_reader (v3) David Malcolm
@ 2016-10-05 16:00   ` Bernd Schmidt
  2016-10-07 13:44     ` David Malcolm
  0 siblings, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-05 16:00 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/05/2016 06:15 PM, David Malcolm wrote:
> 	* errors.c: Use consistent pattern for bconfig.h vs config.h
> 	includes.
> 	(progname): Wrap with #ifdef GENERATOR_FILE.
> 	(error): Likewise.  Add "error: " to message.
> 	(fatal): Likewise.
> 	(internal_error): Likewise.
> 	(trim_filename): Likewise.
> 	(fancy_abort): Likewise.
> 	* errors.h (struct file_location): Move here from read-md.h.
> 	(file_location::file_location): Likewise.
> 	(error_at): New decl.

Can you split these out into a separate patch as well? I'll require more 
explanation for them and they seem largely independent.


Bernd

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

* Re: [PATCH 08/16] (partially-approved): Introduce selftest::locate_file
  2016-10-05 15:44 ` [PATCH 08/16] (partially-approved): Introduce selftest::locate_file David Malcolm
@ 2016-10-05 16:10   ` Bernd Schmidt
  0 siblings, 0 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-05 16:10 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/05/2016 06:15 PM, David Malcolm wrote:
>  selftest: s-selftest
>  s-selftest: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
> -	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test
> +	$(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test=$(srcdir)
>  	$(STAMP) $@

I suspect the Makefile parts will need updating once Thomas commits his 
change.

Also,

> +  return concat (path_to_src_gcc, "/testsuite/selftests/", name, NULL);

why hardcode directory names here? I think this should just be passed as 
a full pathname so only the Makefiles have knowledge of source directory 
structure.


Bernd

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

* Re: [PATCH 16/16] Add "__RTL" to cc1
  2016-10-05 15:45 ` [PATCH 16/16] Add "__RTL" to cc1 David Malcolm
@ 2016-10-05 16:10   ` Joseph Myers
  2016-10-07 15:27     ` [PATCH] Add "__RTL" to cc1 (v2) David Malcolm
  0 siblings, 1 reply; 96+ messages in thread
From: Joseph Myers @ 2016-10-05 16:10 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches

On Wed, 5 Oct 2016, David Malcolm wrote:

> @@ -1752,6 +1759,35 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>        c_parser_skip_to_end_of_block_or_statement (parser);
>        return;
>      }
> +
> +  if (c_parser_next_token_is (parser, CPP_KEYWORD))
> +    {
> +      c_token *kw_token = c_parser_peek_token (parser);
> +      if (kw_token->keyword == RID_RTL)

if (c_parser_next_token_is_keyword (parser, RID_RTL))

You're missing an update to the comment above this function to show what 
the new syntax is.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader
  2016-10-05 15:45 ` [PATCH 15/16] RTL frontend (rtl1), on top of dump reader David Malcolm
@ 2016-10-06 13:30   ` Bernd Schmidt
  2016-10-06 19:53     ` RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader) David Malcolm
  2016-10-20 13:55     ` INSN_UIDs " David Malcolm
  2016-10-06 15:24   ` [PATCH 15/16] RTL frontend (rtl1), on top of dump reader Bernd Schmidt
  1 sibling, 2 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-06 13:30 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/05/2016 06:15 PM, David Malcolm wrote:
> +;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
> +(insn 1045 0 1046 2 (set (reg:SI 480)
> +        (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
> +                    [flags 0xc0]
> +                    <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
> +     y.c:12702 -1
> +     (nil))
> +(insn 1046 1045 1047 2 (set (reg/f:SI 479)
> +        (lo_sum:SI (reg:SI 480)
> +            (symbol_ref:SI ("isl_obj_map_vtable")
> +               [flags 0xc0]
> +               <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
> +     y.c:12702 -1
> +     (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
> +                             [flags 0xc0]
> +                             <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)
> +        (nil)))

I hate saying this, since you've obviously spent a lot of effort, but I 
think we're still at a too early stage to construct testcases. One issue 
that came up while discussing previous patch kits is that the format 
here is still too verbose, and I'd like to settle on a format first. 
There's all manner of things that are pointless in a testcase and impede 
readability:

  * INSN_UIDs and NEXT/PREV fields (could be constructed from scratch,
    except for labels)
  * INSN_CODE_NUMBERs in both textual and number form.
  * Various (nil) fields
  * VAR_DECL addresses.

What does the RTL reader actually do with MEM_ATTRs? Do these survive 
the dump/read process?

There was also a testcase where virtual regs still occurred with 
register number, I think it would be best to disallow this and add the 
ability to parse "(reg:DI virtual-outgoing-args)".

Also I think I'd prefer testcases submitted separately from the RTL 
frontend. It seems we have two different frontend approaches here, one 
RTL frontend and one modification for the C frontend - which do you prefer?


Bernd

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

* Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader
  2016-10-05 15:45 ` [PATCH 15/16] RTL frontend (rtl1), on top of dump reader David Malcolm
  2016-10-06 13:30   ` Bernd Schmidt
@ 2016-10-06 15:24   ` Bernd Schmidt
  2016-10-07 16:22     ` [PATCH] RTL frontend (rtl1), on top of dump reader (v4) David Malcolm
  1 sibling, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-06 15:24 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

Let me just make a first pass over this for minor/obvious issues.

> +we have little control of the input to that specific pass.  We

"control over" maybe?

> +The testsuite is below @file{gcc/testsuite/rtl.dg}.

Not sure this needs to be in the manual (I have similar doubts about the 
entire motivation section, but I guess we can keep it). Also, "below"?

> +/* rtl-error.c - Replacement for errors.c for use by RTL frontend
> +   Copyright (C) 2016 Free Software Foundation, Inc.

Why have this and not use the normal machinery?

> +
> +static bool
> +rtl_langhook_handle_option (
> +    size_t scode,
> +    const char *arg,
> +    int value ATTRIBUTE_UNUSED,
> +    int kind ATTRIBUTE_UNUSED,
> +    location_t loc ATTRIBUTE_UNUSED,
> +    const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)

Please line up the arguments, including the first, with the open paren.
For hooks I think we're converging towards just not naming unused args.

> +
> +  /*  If -fsingle-pass=PASS_NAME was provided, locate and run PASS_NAME
> +      on cfun, as created above.  */

Comment text indented too much.

> +/* Implementation of LANG_HOOKS_TYPE_FOR_MODE, taken from Go frontend.  */
> +
> +static tree
> +rtl_langhook_type_for_mode (machine_mode mode, int unsignedp)
> +{
> +  tree type;
> +  /* Go has no vector types.  Build them here.  FIXME: It does not
> +     make sense for the middle-end to ask the frontend for a type
> +     which the frontend does not support.  However, at least for now
> +     it is required.  See PR 46805.  */

Hmm, not sure it makes much sense to have comments referencing Go.

> +  if (VECTOR_MODE_P (mode))
> +    {
> +      tree inner;
> +
> +      inner = rtl_langhook_type_for_mode (GET_MODE_INNER (mode), unsignedp);
> +      if (inner != NULL_TREE)
> +	return build_vector_type_for_mode (inner, mode);
> +      return NULL_TREE;
> +    }
> +
> +  // FIXME: This static_cast should be in machmode.h.
> +  enum mode_class mc = static_cast<enum mode_class>(GET_MODE_CLASS(mode));
> +  if (mc == MODE_INT)
> +    return rtl_langhook_type_for_size(GET_MODE_BITSIZE(mode), unsignedp);

Also not really following our coding standards. Presumably this is all 
copied?

> +#include <mpfr.h>

The include list probably wants checking whether everything is really 
necessary; this one stood out as a bit odd (several files).
> +
> +#ifndef GCC_RUN_ONE_RTL_PASS_H
> +#define GCC_RUN_ONE_RTL_PASS_H
> +
> +extern void run_one_rtl_pass_by_name (const char *pass_name);
> +
> +#endif /* GCC_RUN_ONE_RTL_PASS_H */

Do we really need an entire header file for a single declaration?


Bernd

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

* RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-06 13:30   ` Bernd Schmidt
@ 2016-10-06 19:53     ` David Malcolm
  2016-10-06 19:59       ` David Malcolm
  2016-10-07 10:38       ` Bernd Schmidt
  2016-10-20 13:55     ` INSN_UIDs " David Malcolm
  1 sibling, 2 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-06 19:53 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches

On Thu, 2016-10-06 at 15:30 +0200, Bernd Schmidt wrote:
> On 10/05/2016 06:15 PM, David Malcolm wrote:
> > +;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
> > +(insn 1045 0 1046 2 (set (reg:SI 480)
> > +        (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
> > +                    [flags 0xc0]
> > +                    <var_decl 0x7fa0363ea240
> > isl_obj_map_vtable>)))
> > +     y.c:12702 -1
> > +     (nil))
> > +(insn 1046 1045 1047 2 (set (reg/f:SI 479)
> > +        (lo_sum:SI (reg:SI 480)
> > +            (symbol_ref:SI ("isl_obj_map_vtable")
> > +               [flags 0xc0]
> > +               <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
> > +     y.c:12702 -1
> > +     (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
> > +                             [flags 0xc0]
> > +                             <var_decl 0x7fa0363ea240
> > isl_obj_map_vtable>)
> > +        (nil)))
> 
> I hate saying this, since you've obviously spent a lot of effort, but
> I 
> think we're still at a too early stage to construct testcases. One
> issue 
> that came up while discussing previous patch kits is that the format 
> here is still too verbose, and I'd like to settle on a format first. 

We have to construct testcases in order to see what the testcase format
should look like - it's hard to talk about things without examples.

> There's all manner of things that are pointless in a testcase and
> impede 
> readability:
> 
>   * INSN_UIDs and NEXT/PREV fields (could be constructed from
> scratch,
>     except for labels)

A benefit of keeping the INSN_UIDs is that if you've spent half an hour
single-stepping through RTL modification and know that INSN_UID 1045 is
the one that gets corrupted, you can have that insn have UID 1045 in
the testcase.  Otherwise the UIDs get determined by the parser, and can
change if other insns get inserted.

Explicit UIDs let you refer to specific insns when discussing a test
case.

>   * INSN_CODE_NUMBERs in both textual and number form.
>   * Various (nil) fields

FWIW these (nil) fields signify the end of various expr_list chains.
If we emit them, there are places in the format where it would become
ambiguous as to which field is getting an expr_list.

>   * VAR_DECL addresses.

Here's a revised version of that example
(gcc/testsuite/rtl.dg/aarch64/pr71779.rtl), with the things you mention
removed, and with some indentation to aid readability:

;; { dg-do compile { target aarch64-*-* } }
;; { dg-options "-fsingle-pass=rtl-cse1 -fdump-rtl-cse1" }

(function "fragment"
  (insn-chain
    ;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
    (insn 2 (set (reg:SI 480)
                 (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
                              [flags 0xc0] <var_decl isl_obj_map_vtable>)))
      y.c:12702)
    (insn 2 (set (reg/f:SI 479)
                 (lo_sum:SI (reg:SI 480)
                            (symbol_ref:SI ("isl_obj_map_vtable")
                               [flags 0xc0]
                               <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
      y.c:12702
      (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
                            [flags 0xc0]
                            <var_decl isl_obj_map_vtable>)))
    (insn 2 (set (reg:DI 481)
                 (subreg:DI (reg/f:SI 479) 0)) y.c:12702)
    (insn 2 (set (zero_extract:DI (reg/v:DI 191 [ obj1D.17368 ])
                                  (const_int 32 [0x20])
                                  (const_int 0 [0]))
                 (reg:DI 481)) y.c:12702)
    ;; Extra insn, to avoid all of the above from being deleted by DCE
    (insn 2 (set (mem:DI (reg:DI 191) [1 i+0 S4 A32])
                         (const_int 1 [0x1])))

  ) ;; insn-chain
) ;; function

This is with the optional cfg and crtl directives omitted.

Does the above look acceptable?

The "2" values after each "insn" are the basic block indices.  Should
these be omitted also?

My hope here is to that the input format is something that existing gcc
developers will be comfortable reading, which is why I opted for
parsing the existing output - and I'm nervous about moving away too
much from the existing format.  In particular, I want the format to be
something that can be automatically printed and roundtripped, and for
it to be useful to look at when in the debugger.

Some other possible changes: locations could do with a wrapper, and/or
to quote the filename, since otherwise we can't cope with spaces in
filenames).  So instead of:

    (insn 2 (set (reg:DI 481)
                 (subreg:DI (reg/f:SI 479)
0)) y.c:12702)

we could have:

    (insn 2 (set (reg:DI 481)
                 (subreg:DI (reg/f:SI 479) 0)) "y.c":12702)

or:

    (insn 2 (set (reg:DI 481)
                 (subreg:DI (reg/f:SI 479)
0)) (srcloc "y.c" 12702))

Any preferences on these?

> What does the RTL reader actually do with MEM_ATTRs?

It parses them, where it can parse the MEM_EXPR, at least (it can only
handle simple decl names for MEM_EXPR).

> Do these survive 
> the dump/read process?

Yes, for the MEM_EXPR cases above.  So it will successfully parse the
"[1 i+0 S4 A32]" above.

> There was also a testcase where virtual regs still occurred with 
> register number, I think it would be best to disallow this and add
> the 
> ability to parse "(reg:DI virtual-outgoing-args)".

When we discussing pseudos you expressed a need to keep printing the
regno for REGs, so that the dump format is usable in the debugger, for
array indices etc.  Hence I'd prefer to keep printing the regno for all
regnos, including virtuals.

> Also I think I'd prefer testcases submitted separately from the RTL 
> frontend. It seems we have two different frontend approaches here,
> one 
> RTL frontend and one modification for the C frontend - which do you
> prefer?

Is it acceptable to do both?  I'd like to have an actual RTL frontend,
though this punts on handling structs etc, whereas Richi seems to
prefer the modification to the C frontend, since it better supports
structs, aliasing, etc.  At this point, whichever gets me past patch
review...

Dave

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

* Re: RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-06 19:53     ` RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader) David Malcolm
@ 2016-10-06 19:59       ` David Malcolm
  2016-10-07 10:38       ` Bernd Schmidt
  1 sibling, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-06 19:59 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches

On Thu, 2016-10-06 at 15:53 -0400, David Malcolm wrote:
> On Thu, 2016-10-06 at 15:30 +0200, Bernd Schmidt wrote:
> > On 10/05/2016 06:15 PM, David Malcolm wrote:
> > > +;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
> > > +(insn 1045 0 1046 2 (set (reg:SI 480)
> > > +        (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
> > > +                    [flags 0xc0]
> > > +                    <var_decl 0x7fa0363ea240
> > > isl_obj_map_vtable>)))
> > > +     y.c:12702 -1
> > > +     (nil))
> > > +(insn 1046 1045 1047 2 (set (reg/f:SI 479)
> > > +        (lo_sum:SI (reg:SI 480)
> > > +            (symbol_ref:SI ("isl_obj_map_vtable")
> > > +               [flags 0xc0]
> > > +               <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
> > > +     y.c:12702 -1
> > > +     (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
> > > +                             [flags 0xc0]
> > > +                             <var_decl 0x7fa0363ea240
> > > isl_obj_map_vtable>)
> > > +        (nil)))
> > 
> > I hate saying this, since you've obviously spent a lot of effort,
> > but
> > I 
> > think we're still at a too early stage to construct testcases. One
> > issue 
> > that came up while discussing previous patch kits is that the
> > format 
> > here is still too verbose, and I'd like to settle on a format
> > first. 
> 
> We have to construct testcases in order to see what the testcase
> format
> should look like - it's hard to talk about things without examples.
> 
> > There's all manner of things that are pointless in a testcase and
> > impede 
> > readability:
> > 
> >   * INSN_UIDs and NEXT/PREV fields (could be constructed from
> > scratch,
> >     except for labels)
> 
> A benefit of keeping the INSN_UIDs is that if you've spent half an
> hour
> single-stepping through RTL modification and know that INSN_UID 1045
> is
> the one that gets corrupted, you can have that insn have UID 1045 in
> the testcase.  Otherwise the UIDs get determined by the parser, and
> can
> change if other insns get inserted.
> 
> Explicit UIDs let you refer to specific insns when discussing a test
> case.
> 
> >   * INSN_CODE_NUMBERs in both textual and number form.
> >   * Various (nil) fields
> 
> FWIW these (nil) fields signify the end of various expr_list chains.
> If we emit them, there are places in the format where it would become
> ambiguous as to which field is getting an expr_list.
> 
> >   * VAR_DECL addresses.
> 
> Here's a revised version of that example
> (gcc/testsuite/rtl.dg/aarch64/pr71779.rtl), with the things you
> mention
> removed, and with some indentation to aid readability:
> 
> ;; { dg-do compile { target aarch64-*-* } }
> ;; { dg-options "-fsingle-pass=rtl-cse1 -fdump-rtl-cse1" }
> 
> (function "fragment"
>   (insn-chain
>     ;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
>     (insn 2 (set (reg:SI 480)
>                  (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
>                               [flags 0xc0] <var_decl
> isl_obj_map_vtable>)))
>       y.c:12702)
>     (insn 2 (set (reg/f:SI 479)
>                  (lo_sum:SI (reg:SI 480)
>                             (symbol_ref:SI ("isl_obj_map_vtable")
>                                [flags 0xc0]
>                                <var_decl 0x7fa0363ea240
> isl_obj_map_vtable>)))
>       y.c:12702
>       (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
>                             [flags 0xc0]
>                             <var_decl isl_obj_map_vtable>)))
>     (insn 2 (set (reg:DI 481)
>                  (subreg:DI (reg/f:SI 479) 0)) y.c:12702)
>     (insn 2 (set (zero_extract:DI (reg/v:DI 191 [ obj1D.17368 ])
>                                   (const_int 32 [0x20])
>                                   (const_int 0 [0]))
>                  (reg:DI 481)) y.c:12702)
>     ;; Extra insn, to avoid all of the above from being deleted by
> DCE
>     (insn 2 (set (mem:DI (reg:DI 191) [1 i+0 S4 A32])
>                          (const_int 1 [0x1])))
> 
>   ) ;; insn-chain
> ) ;; function
> 
> This is with the optional cfg and crtl directives omitted.
> 
> Does the above look acceptable?
> 
> The "2" values after each "insn" are the basic block indices.  Should
> these be omitted also?

If we do that, one approach could be to introduce a (basic-block)
directive into the (insn-chain), giving something like this:

;; { dg-do compile { target aarch64-*-* } }
;; { dg-options "-fsingle-pass=rtl-cse1 -fdump-rtl-cse1" }

(function "fragment"
  (insn-chain
    (basic-block 2
      ;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
      (insn (set (reg:SI 480)
                 (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
                              [flags 0xc0] <var_decl isl_obj_map_vtable>)))
        y.c:12702)
      (insn (set (reg/f:SI 479)
                 (lo_sum:SI (reg:SI 480)
                            (symbol_ref:SI ("isl_obj_map_vtable")
                               [flags 0xc0]
                               <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
        y.c:12702
        (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
                              [flags 0xc0]
                              <var_decl isl_obj_map_vtable>)))
      (insn (set (reg:DI 481)
                 (subreg:DI (reg/f:SI 479) 0)) y.c:12702)
      (insn (set (zero_extract:DI (reg/v:DI 191 [ obj1D.17368 ])
                                  (const_int 32 [0x20])
                                  (const_int 0 [0]))
                 (reg:DI 481)) y.c:12702)
      ;; Extra insn, to avoid all of the above from being deleted by DCE
      (insn (set (mem:DI (reg:DI 191) [1 i+0 S4 A32])
                         (const_int 1 [0x1])))
    ) ;; basic-block 2
  ) ;; insn-chain
) ;; function

> My hope here is to that the input format is something that existing
> gcc
> developers will be comfortable reading, which is why I opted for
> parsing the existing output - and I'm nervous about moving away too
> much from the existing format.  In particular, I want the format to
> be
> something that can be automatically printed and roundtripped, and for
> it to be useful to look at when in the debugger.
> 
> Some other possible changes: locations could do with a wrapper,
> and/or
> to quote the filename, since otherwise we can't cope with spaces in
> filenames).  So instead of:
> 
>     (insn 2 (set (reg:DI 481)
>                  (subreg:DI (reg/f:SI 479)
> 0)) y.c:12702)
> 
> we could have:
> 
>     (insn 2 (set (reg:DI 481)
>                  (subreg:DI (reg/f:SI 479) 0)) "y.c":12702)
> 
> or:
> 
>     (insn 2 (set (reg:DI 481)
>                  (subreg:DI (reg/f:SI 479)
> 0)) (srcloc "y.c" 12702))
> 
> Any preferences on these?
> 
> > What does the RTL reader actually do with MEM_ATTRs?
> 
> It parses them, where it can parse the MEM_EXPR, at least (it can
> only
> handle simple decl names for MEM_EXPR).
> 
> > Do these survive 
> > the dump/read process?
> 
> Yes, for the MEM_EXPR cases above.  So it will successfully parse the
> "[1 i+0 S4 A32]" above.
> 
> > There was also a testcase where virtual regs still occurred with 
> > register number, I think it would be best to disallow this and add
> > the 
> > ability to parse "(reg:DI virtual-outgoing-args)".
> 
> When we discussing pseudos you expressed a need to keep printing the
> regno for REGs, so that the dump format is usable in the debugger,
> for
> array indices etc.  Hence I'd prefer to keep printing the regno for
> all
> regnos, including virtuals.
> 
> > Also I think I'd prefer testcases submitted separately from the RTL
> > frontend. It seems we have two different frontend approaches here,
> > one 
> > RTL frontend and one modification for the C frontend - which do you
> > prefer?
> 
> Is it acceptable to do both?  I'd like to have an actual RTL
> frontend,
> though this punts on handling structs etc, whereas Richi seems to
> prefer the modification to the C frontend, since it better supports
> structs, aliasing, etc.  At this point, whichever gets me past patch
> review...
> 
> Dave

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

* Re: RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-06 19:53     ` RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader) David Malcolm
  2016-10-06 19:59       ` David Malcolm
@ 2016-10-07 10:38       ` Bernd Schmidt
  2016-10-07 13:27         ` David Malcolm
  1 sibling, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-07 10:38 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/06/2016 09:53 PM, David Malcolm wrote:
> A benefit of keeping the INSN_UIDs is that if you've spent half an hour
> single-stepping through RTL modification and know that INSN_UID 1045 is
> the one that gets corrupted, you can have that insn have UID 1045 in
> the testcase.  Otherwise the UIDs get determined by the parser, and can
> change if other insns get inserted.

That's true, but you wouldn't construct a testcase until you're done 
debugging, and this reason is lost for any testcase that has been 
committed to the repository for more than say a week. I think we want a 
format that is lean and abstracts away unnecessary details.
>
> Here's a revised version of that example
> (gcc/testsuite/rtl.dg/aarch64/pr71779.rtl), with the things you mention
> removed, and with some indentation to aid readability:
>
> ;; { dg-do compile { target aarch64-*-* } }
> ;; { dg-options "-fsingle-pass=rtl-cse1 -fdump-rtl-cse1" }
>
> (function "fragment"
>   (insn-chain
>     ;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
>     (insn 2 (set (reg:SI 480)
>                  (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
>                               [flags 0xc0] <var_decl isl_obj_map_vtable>)))
>       y.c:12702)
>     (insn 2 (set (reg/f:SI 479)
>                  (lo_sum:SI (reg:SI 480)
>                             (symbol_ref:SI ("isl_obj_map_vtable")
>                                [flags 0xc0]
>                                <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
>       y.c:12702
>       (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
>                             [flags 0xc0]
>                             <var_decl isl_obj_map_vtable>)))
>     (insn 2 (set (reg:DI 481)
>                  (subreg:DI (reg/f:SI 479) 0)) y.c:12702)
>     (insn 2 (set (zero_extract:DI (reg/v:DI 191 [ obj1D.17368 ])
>                                   (const_int 32 [0x20])
>                                   (const_int 0 [0]))
>                  (reg:DI 481)) y.c:12702)
>     ;; Extra insn, to avoid all of the above from being deleted by DCE
>     (insn 2 (set (mem:DI (reg:DI 191) [1 i+0 S4 A32])
>                          (const_int 1 [0x1])))
>
>   ) ;; insn-chain
> ) ;; function
>
> This is with the optional cfg and crtl directives omitted.
>
> Does the above look acceptable?

One thing this doesn't show is CODE_LABELs, which will need some sort of 
unique identifier.

There's still the 0x7fa0363ea240 for the var-decl. You want the 
dump-noaddr flag.

> The "2" values after each "insn" are the basic block indices.  Should
> these be omitted also?

I think they probably don't buy us much if we have block notes.

What about file names/line numbers? We'll probably want some tests for 
these, but for most others they will be irrelevant.

I think maybe you want a separate compact form of insns and notes 
(cinsn/cnote maybe), with a flag selecting which gets written out in the 
dumper. The reader could then read them in like any other rtx code, and 
there'd be a postprocessing stage to reconstruct the insn chain.

> My hope here is to that the input format is something that existing gcc
> developers will be comfortable reading, which is why I opted for
> parsing the existing output - and I'm nervous about moving away too
> much from the existing format.

Hey, I'm as existing a gcc developer as they come, and I don't much like 
staring at unpruned rtl dumps. They've gotten worse over the years too.

> Some other possible changes: locations could do with a wrapper, and/or
> to quote the filename, since otherwise we can't cope with spaces in
> filenames).  So instead of:
>
>     (insn 2 (set (reg:DI 481)
>                  (subreg:DI (reg/f:SI 479)
> 0)) y.c:12702)
>
> we could have:
>
>     (insn 2 (set (reg:DI 481)
>                  (subreg:DI (reg/f:SI 479) 0)) "y.c":12702)
>
> or:
>
>     (insn 2 (set (reg:DI 481)
>                  (subreg:DI (reg/f:SI 479)
> 0)) (srcloc "y.c" 12702))
>
> Any preferences on these?

I suspect just putting it in quotes is good enough. Might be worth doing 
that in general.

>> There was also a testcase where virtual regs still occurred with
>> register number, I think it would be best to disallow this and add
>> the
>> ability to parse "(reg:DI virtual-outgoing-args)".
>
> When we discussing pseudos you expressed a need to keep printing the
> regno for REGs, so that the dump format is usable in the debugger, for
> array indices etc.  Hence I'd prefer to keep printing the regno for all
> regnos, including virtuals.

This comes back to different needs for long-lived testcases vs. 
debugging something. As suggested above, I think you need a flag for 
different output formats, and for vregs the ability to parse "(reg:M 
virtual-something)".

>> Also I think I'd prefer testcases submitted separately from the RTL
>> frontend. It seems we have two different frontend approaches here,
>> one
>> RTL frontend and one modification for the C frontend - which do you
>> prefer?
>
> Is it acceptable to do both?  I'd like to have an actual RTL frontend,
> though this punts on handling structs etc, whereas Richi seems to
> prefer the modification to the C frontend, since it better supports
> structs, aliasing, etc.  At this point, whichever gets me past patch
> review...

Does the C one have an advantage in terms of meaningful decls in 
MEM_ATTRs/SYMBOL_REFs?


Bernd

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

* Re: RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-07 10:38       ` Bernd Schmidt
@ 2016-10-07 13:27         ` David Malcolm
  2016-10-07 13:58           ` Bernd Schmidt
  0 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-07 13:27 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches

On Fri, 2016-10-07 at 12:38 +0200, Bernd Schmidt wrote:
> On 10/06/2016 09:53 PM, David Malcolm wrote:
> > A benefit of keeping the INSN_UIDs is that if you've spent half an
> > hour
> > single-stepping through RTL modification and know that INSN_UID
> > 1045 is
> > the one that gets corrupted, you can have that insn have UID 1045
> > in
> > the testcase.  Otherwise the UIDs get determined by the parser, and
> > can
> > change if other insns get inserted.
> 
> That's true, but you wouldn't construct a testcase until you're done 
> debugging, and this reason is lost for any testcase that has been 
> committed to the repository for more than say a week. I think we want
> a 
> format that is lean and abstracts away unnecessary details.
> > 
> > Here's a revised version of that example
> > (gcc/testsuite/rtl.dg/aarch64/pr71779.rtl), with the things you
> > mention
> > removed, and with some indentation to aid readability:
> > 
> > ;; { dg-do compile { target aarch64-*-* } }
> > ;; { dg-options "-fsingle-pass=rtl-cse1 -fdump-rtl-cse1" }
> > 
> > (function "fragment"
> >   (insn-chain
> >     ;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
> >     (insn 2 (set (reg:SI 480)
> >                  (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
> >                               [flags 0xc0] <var_decl
> > isl_obj_map_vtable>)))
> >       y.c:12702)
> >     (insn 2 (set (reg/f:SI 479)
> >                  (lo_sum:SI (reg:SI 480)
> >                             (symbol_ref:SI ("isl_obj_map_vtable")
> >                                [flags 0xc0]
> >                                <var_decl 0x7fa0363ea240
> > isl_obj_map_vtable>)))
> >       y.c:12702
> >       (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
> >                             [flags 0xc0]
> >                             <var_decl isl_obj_map_vtable>)))
> >     (insn 2 (set (reg:DI 481)
> >                  (subreg:DI (reg/f:SI 479) 0)) y.c:12702)
> >     (insn 2 (set (zero_extract:DI (reg/v:DI 191 [ obj1D.17368 ])
> >                                   (const_int 32 [0x20])
> >                                   (const_int 0 [0]))
> >                  (reg:DI 481)) y.c:12702)
> >     ;; Extra insn, to avoid all of the above from being deleted by
> > DCE
> >     (insn 2 (set (mem:DI (reg:DI 191) [1 i+0 S4 A32])
> >                          (const_int 1 [0x1])))
> > 
> >   ) ;; insn-chain
> > ) ;; function
> > 
> > This is with the optional cfg and crtl directives omitted.
> > 
> > Does the above look acceptable?
> 
> One thing this doesn't show is CODE_LABELs, which will need some sort
> of 
> unique identifier.

Note that all of my examples are hand-edited, so there may be mistakes,
inconsistencies, etc.

We could simply print the INSN_UID for CODE_LABELs; something like this
(see the "(code_label 16" below):

  (jump_insn (set (pc)
          (if_then_else (ge (reg:CCGC 17 flags)
                  (const_int 0 [0]))
              (label_ref 16)
              (pc))) "test.c":3
       
   -> 16)
  (note [bb 4] NOTE_INSN_BASIC_BLOCK)
  (insn (set (reg:SI 90)
        (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
                  (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) "test.c":4
       )
  (insn (parallel [
              (set (reg:SI 87 [ _1 ])
                  (plus:SI (reg:SI 90)
                      (const_int 4 [0x4])))
              (clobber (reg:CC 17 flags))
          ]) "test.c":4
       (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
                      (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
              (const_int 4 [0x4]))
          ))
  (jump_insn (set (pc) (label_ref 20)) "test.c":4       
   -> 20)
  (barrier)
  (code_label 16 [1 uses])
  (note [bb 5] NOTE_INSN_BASIC_BLOCK)

Should we drop the "[1 uses]" in the code_label?

> There's still the 0x7fa0363ea240 for the var-decl. You want the 
> dump-noaddr flag.

(indeed; I'm hand-editing the examples)

> > The "2" values after each "insn" are the basic block indices. 
> >  Should
> > these be omitted also?
> 
> I think they probably don't buy us much if we have block notes.

Unfortunately, the (code_label 16) above is in basic block *5*, not
basic_block 4 i.e. as you traverse the insn chaing the change of basic
block can happen before the NOTE_INSN_BASIC_BLOCK.  There is a barrier
and a code_label, but even so, this seems rather counter-intuitive to
me.

You appear to have trimmed the idea of enclosing the insns with (basic-block) directives without commenting on it.  Did you like this idea?
It would make the above look like:

  (basic-block 2
    ;; insns snipped
    (jump_insn (set (pc)
            (if_then_else (ge (reg:CCGC 17 flags)
                    (const_int 0 [0]))
                (label_ref 16)
                (pc))) "test.c":3
   -> 16)
  ) ;; basic-block 2
  (basic-block 4
    (note [bb 4] NOTE_INSN_BASIC_BLOCK)
    ;; insns snipped
    (jump_insn (set (pc) (label_ref 20)) "test.c":4       
     -> 20)
  ) ;; basic-block 4
  (barrier)
  (basic-block 5
    (code_label 16 [1 uses])
    (note [bb 5] NOTE_INSN_BASIC_BLOCK)
    ;; etc
  ) ;; basic-block 5

Note how the above format expresses clearly that:
* the (barrier) is part of the insn chain, but not in a basic block, and
* some insns can happen in a basic block

Taking this idea further: if we have (basic-block) directives integrated into the insn-chain like this, we could express the CFG by adding (edge) directives.  Here's a suggestion for doing it with (edge-from) and (edge-to) directives, expressing the predecessor and successor edges in the CFG, along with :

  (basic-block 2
    (edge-from 0)
    ;; insns snipped
    (jump_insn (set (pc)
            (if_then_else (ge (reg:CCGC 17 flags)
                    (const_int 0 [0]))
                (label_ref 16)
                (pc))) "test.c":3
   -> 16)
    (edge-to 4 (flags "FALLTHRU"))
    (edge-to 5 (flags ""))
  ) ;; basic-block 2
  (basic-block 4
    (edge-from 2 (flags "FALLTHRU"))
    (note [bb 4] NOTE_INSN_BASIC_BLOCK)
    ;; some insns snipped
    (jump_insn (set (pc) (label_ref 20)) "test.c":4       
     -> 20)
    (edge-to 6 (flags ""))
  ) ;; basic-block 4
  (barrier)
  (basic-block 5
    (edge-from 2 (flags ""))
    (code_label 16 [1 uses])
    (note [bb 5] NOTE_INSN_BASIC_BLOCK)
    ;; some insns snipped
    (edge-to 6 (flags ""))
  ) ;; basic-block 5


Do you like this approach?   It could also support insns that are on
edges (though I don't know if that's something we need to support in
dumps).

Should we spell "0" and "1" as "entry" and "exit" when parsing/dumping
basic block indices? e.g.:

  (basic-block 2
    (edge-from entry)

> What about file names/line numbers? We'll probably want some tests
> for 
> these, but for most others they will be irrelevant.

Yeah.  We cover this below.

> I think maybe you want a separate compact form of insns and notes 
> (cinsn/cnote maybe), with a flag selecting which gets written out in
> the 
> dumper. The reader could then read them in like any other rtx code,
> and 
> there'd be a postprocessing stage to reconstruct the insn chain.

By this separate compact form, do you mean the form we've been
discussing above, with no INSN_UID/PREV/NEXT, etc?  Or something else?

As for "cinsn", "cnote", how about just "insn" and "note", and having
the compactness be expressed at the top of the dump e.g. implicitly by
the presence of a "(function" directive.  Could even have a format
version specifier in the function directive, to give us some future
-proofing e.g.
  (function (format 20161007)
or somesuch.

> > My hope here is to that the input format is something that existing
> > gcc
> > developers will be comfortable reading, which is why I opted for
> > parsing the existing output - and I'm nervous about moving away too
> > much from the existing format.
> 
> Hey, I'm as existing a gcc developer as they come, and I don't much
> like 
> staring at unpruned rtl dumps. They've gotten worse over the years
> too.

Fair enough :)

Do you want to want to try hand-edited a test case, using some of the
format ideas we've been discussing?  That might suggest further
improvements to the format.

> > Some other possible changes: locations could do with a wrapper,
> > and/or
> > to quote the filename, since otherwise we can't cope with spaces in
> > filenames).  So instead of:
> > 
> >     (insn 2 (set (reg:DI 481)
> >                  (subreg:DI (reg/f:SI 479)
> > 0)) y.c:12702)
> > 
> > we could have:
> > 
> >     (insn 2 (set (reg:DI 481)
> >                  (subreg:DI (reg/f:SI 479) 0)) "y.c":12702)
> > 
> > or:
> > 
> >     (insn 2 (set (reg:DI 481)
> >                  (subreg:DI (reg/f:SI 479)
> > 0)) (srcloc "y.c" 12702))
> > 
> > Any preferences on these?
> 
> I suspect just putting it in quotes is good enough. Might be worth
> doing 
> that in general.

Good.  Let's quote the filenames.

> > > There was also a testcase where virtual regs still occurred with
> > > register number, I think it would be best to disallow this and
> > > add
> > > the
> > > ability to parse "(reg:DI virtual-outgoing-args)".
> > 
> > When we discussing pseudos you expressed a need to keep printing
> > the
> > regno for REGs, so that the dump format is usable in the debugger,
> > for
> > array indices etc.  Hence I'd prefer to keep printing the regno for
> > all
> > regnos, including virtuals.
> 
> This comes back to different needs for long-lived testcases vs. 
> debugging something. As suggested above, I think you need a flag for 
> different output formats, and for vregs the ability to parse "(reg:M 
> virtual-something)".

OK.  If so, do we need to print the regno for hard registers?  Or
should we just print the name for those, for consistency with virtual
regs?  (i.e. have it be controlled by the same flag?)

> > > Also I think I'd prefer testcases submitted separately from the
> > > RTL
> > > frontend. It seems we have two different frontend approaches
> > > here,
> > > one
> > > RTL frontend and one modification for the C frontend - which do
> > > you
> > > prefer?
> > 
> > Is it acceptable to do both?  I'd like to have an actual RTL
> > frontend,
> > though this punts on handling structs etc, whereas Richi seems to
> > prefer the modification to the C frontend, since it better supports
> > structs, aliasing, etc.  At this point, whichever gets me past
> > patch
> > review...
> 
> Does the C one have an advantage in terms of meaningful decls in 
> MEM_ATTRs/SYMBOL_REFs?

Probably.

Thanks
Dave

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

* Re: [PATCH 10/16] Introduce class function_reader (v3)
  2016-10-05 16:00   ` Bernd Schmidt
@ 2016-10-07 13:44     ` David Malcolm
  2016-10-10 18:53       ` Richard Sandiford
  0 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-07 13:44 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: Richard Sandiford

On Wed, 2016-10-05 at 18:00 +0200, Bernd Schmidt wrote:
> On 10/05/2016 06:15 PM, David Malcolm wrote:
> > 	* errors.c: Use consistent pattern for bconfig.h vs config.h
> > 	includes.
> > 	(progname): Wrap with #ifdef GENERATOR_FILE.
> > 	(error): Likewise.  Add "error: " to message.
> > 	(fatal): Likewise.
> > 	(internal_error): Likewise.
> > 	(trim_filename): Likewise.
> > 	(fancy_abort): Likewise.
> > 	* errors.h (struct file_location): Move here from read-md.h.
> > 	(file_location::file_location): Likewise.
> > 	(error_at): New decl.
> 
> Can you split these out into a separate patch as well? I'll require
> more 
> explanation for them and they seem largely independent.

[CCing Richard Sandiford]

The gen* tools have their own diagnostics system, in errors.c:

/* warning, error, and fatal.  These definitions are suitable for use
   in the generator programs; the compiler has a more elaborate suite
   of diagnostic printers, found in diagnostic.c.  */

with file locations tracked using read-md.h's struct file_location,
rather than location_t (aka libcpp's source_location).

Implementing an RTL frontend by using the RTL reader from read-rtl.c
means that we now need a diagnostics subsystem on the *host* for
handling errors in RTL files, rather than just on the build machine.

There seem to be two ways to do this:

  (A) build the "light" diagnostics system (errors.c) for the host as
well as build machine, and link it with the RTL reader there, so there
are two parallel diagnostics subsystems.

  (B) build the "real" diagnostics system (diagnostics*) for the
*build* machine as well as the host, and use it from the gen* tools,
eliminating the "light" system, and porting the gen* tools to use
libcpp for location tracking.

Approach (A) seems to be simpler, which is what this part of the patch
does.

I've experimented with approach (B).  I think it's doable, but it's
much more invasive (perhaps needing a libdiagnostics.a and a
build/libdiagnostics.a in gcc/Makefile.in), so I hope this can be
followup work.

I can split the relevant parts out into a separate patch, but I was
wondering if either of you had a strong opinion on (A) vs (B) before I
do so?

Dave

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

* Re: RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-07 13:27         ` David Malcolm
@ 2016-10-07 13:58           ` Bernd Schmidt
  2016-10-07 18:08             ` David Malcolm
                               ` (3 more replies)
  0 siblings, 4 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-07 13:58 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/07/2016 03:26 PM, David Malcolm wrote:
>
> We could simply print the INSN_UID for CODE_LABELs; something like this
> (see the "(code_label 16" below):

I think that should work.

> You appear to have trimmed the idea of enclosing the insns with
> (basic-block) directives without commenting on it.  Did you like this
> idea?

Sorry - I appear to have completely missed it.

> It would make the above look like:
>
>   (basic-block 2
>     ;; insns snipped
>     (jump_insn (set (pc)
>             (if_then_else (ge (reg:CCGC 17 flags)
>                     (const_int 0 [0]))
>                 (label_ref 16)
>                 (pc))) "test.c":3
>    -> 16)
>   ) ;; basic-block 2
>   (basic-block 4
>     (note [bb 4] NOTE_INSN_BASIC_BLOCK)
>     ;; insns snipped
>     (jump_insn (set (pc) (label_ref 20)) "test.c":4
>      -> 20)
>   ) ;; basic-block 4
>   (barrier)
>   (basic-block 5
>     (code_label 16 [1 uses])
>     (note [bb 5] NOTE_INSN_BASIC_BLOCK)
>     ;; etc
>   ) ;; basic-block 5
>
> Note how the above format expresses clearly that:
> * the (barrier) is part of the insn chain, but not in a basic block, and
> * some insns can happen in a basic block

That looks really nice IMO. Except maybe drop the "-> 16" bit for the 
jump_insn (that's the JUMP_LABEL, isn't it?)

> Taking this idea further: if we have (basic-block) directives
> integrated into the insn-chain like this, we could express the CFG by
> adding (edge) directives. Here's a suggestion for doing it with
> (edge-from) and (edge-to) directives, expressing the predecessor and
> successor edges in the CFG, along with :

That also looks reasonable. Probably a small but maybe not a huge 
improvement over the other syntax. Having both from and to edges seems 
redundant but might help readability. The reader should check 
consistency in that case.

> Should we spell "0" and "1" as "entry" and "exit" when parsing/dumping
> basic block indices? e.g.:
>
>   (basic-block 2
>     (edge-from entry)

If that can be done it would be an improvement.

>> I think maybe you want a separate compact form of insns and notes
>> (cinsn/cnote maybe), with a flag selecting which gets written out in
>> the
>> dumper. The reader could then read them in like any other rtx code,
>> and
>> there'd be a postprocessing stage to reconstruct the insn chain.
>
> By this separate compact form, do you mean the form we've been
> discussing above, with no INSN_UID/PREV/NEXT, etc?  Or something else?

Yes, the form we're discussing, except instead of (insn ...) you'd have 
(cinsn ...), which I assume would make it easier for the reader and less 
ambiguous overall.

> As for "cinsn", "cnote", how about just "insn" and "note", and having
> the compactness be expressed at the top of the dump e.g. implicitly by
> the presence of a "(function" directive.  Could even have a format
> version specifier in the function directive, to give us some future
> -proofing e.g.
>   (function (format 20161007)
> or somesuch.

Having it implicit should also be ok - I have no strong preference 
really. I'm not sure we want versioning - better to have an automatic 
conversion if we ever feel we need to change the format.

> Do you want to want to try hand-edited a test case, using some of the
> format ideas we've been discussing?  That might suggest further
> improvements to the format.

We'll definitely want to have a look at one or two. Also, we ought to 
try to set up situations we haven't discussed: ADDR_VECs (in light of 
the basic block dumping) and ASMs maybe. I'm probably forgetting some.

One other thing in terms of format is the printout of CONST_INT - I 
think it should suffice to have either decimal, or hex, but not really 
both. The reader should maybe accept either.

I think all hosts have 64-bit HWI these days, so CONST_INT ought to 
always stay valid through a roundtrip.

I may have missed it, but is there any kind of provision yet for 
providing an "after" dump for what is expected after a pass is run? 
Might be worth thinking about whether the reader could have a mode where 
it matches internal RTL against an input.

> OK.  If so, do we need to print the regno for hard registers?  Or
> should we just print the name for those, for consistency with virtual
> regs?  (i.e. have it be controlled by the same flag?)

Just the name should work, leaving only pseudos with numbers - that 
ought to be reasonable. In the reader, when encountering a reg with a 
number, just add FIRST_PSEUDO_REGISTER, and you should end up with 
something that's consistent. Or maybe even dump the expected 
FIRST_PSEUDO_REGISTER, and adjust for it in case the one we have at 
run-time differs.

>> Does the C one have an advantage in terms of meaningful decls in
>> MEM_ATTRs/SYMBOL_REFs?
>
> Probably.

I think that might be the more promising path then.


Bernd

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

* [PATCH] Add "__RTL" to cc1 (v2)
  2016-10-05 16:10   ` Joseph Myers
@ 2016-10-07 15:27     ` David Malcolm
  2016-10-13 13:49       ` Richard Biener
  0 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-07 15:27 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, David Malcolm

On Wed, 2016-10-05 at 16:09 +0000, Joseph Myers wrote:
> On Wed, 5 Oct 2016, David Malcolm wrote:
> 
> > @@ -1752,6 +1759,35 @@ c_parser_declaration_or_fndef (c_parser
> > *parser, bool fndef_ok,
> >        c_parser_skip_to_end_of_block_or_statement (parser);
> >        return;
> >      }
> > +
> > +  if (c_parser_next_token_is (parser, CPP_KEYWORD))
> > +    {
> > +      c_token *kw_token = c_parser_peek_token (parser);
> > +      if (kw_token->keyword == RID_RTL)
> 
> if (c_parser_next_token_is_keyword (parser, RID_RTL))
> 
> You're missing an update to the comment above this function to show
> what
> the new syntax is.

Thanks.  Here's an updated version of the patch which fixes that,
along with some other fixes:
* Use c_parser_next_token_is_keyword.
* Removed a stray "FIXME".
* Removed some debug code.
* Add more comments
* Fixed a typo in the ChangeLog ("__RID" -> "__RTL")

Blurb from original version:

This patch implements Richi's idea of having a custom __RTL marker
in C function definitions, to indicate that the body of the function
is to be parsed as RTL, rather than C:

int __RTL test_fn_1 (int i)
{
 (function "times_two"
   (insn-chain
     (note 1 0 4 (nil) NOTE_INSN_DELETED)
     ;; etc
   ) ;; insn-chain
   (crtl
     (return_rtx
       (reg/i:SI 0 ax)
     ) ;; return_rtx
   ) ;; crtl
  ) ;; function
}

This allows for decls and types to be declared in C, and to use
the function decl from the C frontend.

I added support for running a single pass by giving __RTL an optional
parameter (the name of the pass).  For example:

int __RTL ("rtl-dfinit") test_fn_2 (int i)
{
 (function "times_two"
   (insn-chain
     (note 1 0 4 (nil) NOTE_INSN_DELETED)
     ;; etc
   ) ;; insn-chain
   (crtl
     (return_rtx
       (reg/i:SI 0 ax)
     ) ;; return_rtx
   ) ;; crtl
  ) ;; function
}

The top-level "function" directive is rather redundant; perhaps it should
be omitted?  This would give e.g.:

int __RTL ("rtl-dfinit") test_fn_3 (int i)
{
   (insn-chain
     (note 1 0 4 (nil) NOTE_INSN_DELETED)
     ;; etc
   ) ;; insn-chain
   (crtl
     (return_rtx
       (reg/i:SI 0 ax)
     ) ;; return_rtx
   ) ;; crtl
}

(Though maybe we want to keep it as a place to hold top-level metadata)

gcc/c-family/ChangeLog:
	* c-common.c (c_common_reswords): Add "__RTL".
	* c-common.h (enum rid): Add RID_RTL.

gcc/c/ChangeLog:
	* c-parser.c: Include "read-rtl-function.h" and
	"run-one-rtl-pass.h".
	(c_parser_declaration_or_fndef): In the "GNU extensions" part of
	the leading comment, add an alternate production for
	"function-definition", along with new "rtl-body-specifier" and
	"rtl-body-pass-specifier" productions.  Handle "__RTL" by calling
	c_parser_parse_rtl_body.  Convert a timevar_push/pop pair
	to an auto_timevar, to cope with early exit.
	(c_parser_parse_rtl_body): New function.

gcc/ChangeLog:
	* read-md.c (base_rtx_reader::read_char): Support filtering
	the input to a subset of line numbers.
	(base_rtx_reader::base_rtx_reader): Initialize fields
	m_first_line and m_last_line.
	(base_rtx_reader::read_file_fragment): New method.
	* read-md.h (base_rtx_reader::read_file_fragment): New decl.
	(base_rtx_reader::m_first_line): New field.
	(base_rtx_reader::m_last_line): New field.
	* read-rtl-function.c (function_reader::create_function): Only create
	cfun if it doesn't already exist.
	(read_rtl_function_body_from_file_range): New function.
	* read-rtl-function.h (read_rtl_function_body_from_file_range):
	New decl.

gcc/testsuite/ChangeLog:
	* rtl.dg/rtl.exp: Add .c files below rtl.dg to "tests".
	* rtl.dg/x86_64/different-structs.c: New file.
	* rtl.dg/x86_64/test-return-const.c.after-expand.c: New file.
	* rtl.dg/x86_64/test-return-const.c.before-fwprop.c: New file.
	* rtl.dg/x86_64/test-rtl.c: New file.
	* rtl.dg/x86_64/times-two.c.after-expand.c: New file.
	* rtl.dg/x86_64/times-two.c.before-df.c: New file.
---
 gcc/c-family/c-common.c                            |   1 +
 gcc/c-family/c-common.h                            |   3 +
 gcc/c/c-parser.c                                   | 113 ++++++++++++++++++++-
 gcc/read-md.c                                      |  34 ++++++-
 gcc/read-md.h                                      |   7 ++
 gcc/read-rtl-function.c                            |  78 ++++++++++----
 gcc/read-rtl-function.h                            |   3 +
 gcc/testsuite/rtl.dg/rtl.exp                       |   4 +-
 gcc/testsuite/rtl.dg/x86_64/different-structs.c    | 101 ++++++++++++++++++
 .../x86_64/test-return-const.c.after-expand.c      |  23 +++++
 .../x86_64/test-return-const.c.before-fwprop.c     |  27 +++++
 gcc/testsuite/rtl.dg/x86_64/test-rtl.c             |  95 +++++++++++++++++
 .../rtl.dg/x86_64/times-two.c.after-expand.c       |  40 ++++++++
 .../rtl.dg/x86_64/times-two.c.before-df.c          |  57 +++++++++++
 14 files changed, 565 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/different-structs.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-rtl.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 491c637..ecef32b 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -524,6 +524,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
   { "__volatile",	RID_VOLATILE,	0 },
   { "__volatile__",	RID_VOLATILE,	0 },
+  { "__RTL",		RID_RTL,	0 },
   { "alignas",		RID_ALIGNAS,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "alignof",		RID_ALIGNOF,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "asm",		RID_ASM,	D_ASM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index c88619b..e19751e 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -118,6 +118,9 @@ enum rid
 
   RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
 
+  /* "__RTL", for the RTL-parsing extension to the C frontend.  */
+  RID_RTL,
+
   /* C11 */
   RID_ALIGNAS, RID_GENERIC,
 
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 6bc42da..693d1bd 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -59,6 +59,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-expr.h"
 #include "context.h"
 #include "gcc-rich-location.h"
+#include "read-rtl-function.h"
+#include "run-one-rtl-pass.h"
 
 /* We need to walk over decls with incomplete struct/union/enum types
    after parsing the whole translation unit.
@@ -1421,6 +1423,9 @@ static tree c_parser_array_notation (location_t, c_parser *, tree, tree);
 static tree c_parser_cilk_clause_vectorlength (c_parser *, tree, bool);
 static void c_parser_cilk_grainsize (c_parser *, bool *);
 
+static void c_parser_parse_rtl_body (c_parser *parser,
+				     const char *single_pass_name);
+
 /* Parse a translation unit (C90 6.7, C99 6.9).
 
    translation-unit:
@@ -1624,6 +1629,16 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
      declaration-specifiers declarator declaration-list[opt]
        compound-statement
 
+   function-definition:
+     declaration-specifiers rtl-body-specifier declarator declaration-list[opt]
+       compound-statement
+
+   rtl-body-specifier:
+     __RTL rtl-body-pass-specifier[opt]
+
+   rtl-body-pass-specifier:
+     ( string )
+
    attribute ;
 
    Objective-C:
@@ -1668,6 +1683,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
   tree all_prefix_attrs;
   bool diagnosed_no_specs = false;
   location_t here = c_parser_peek_token (parser)->location;
+  bool rtl_body_p = false;
+  const char *single_pass_name = NULL;
 
   if (static_assert_ok
       && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
@@ -1752,6 +1769,33 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       c_parser_skip_to_end_of_block_or_statement (parser);
       return;
     }
+
+  /* Handle GNU extension rtl-body-specifier by detecting "__RTL".  */
+  if (c_parser_next_token_is_keyword (parser, RID_RTL))
+    {
+      rtl_body_p = true;
+      c_parser_consume_token (parser);
+
+      /* Handle the optional rtl-body-pass-specifier: parens wrapping
+	 a string, giving a pass name.  */
+      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+	{
+	  c_parser_consume_token (parser);
+	  c_token *tok = c_parser_peek_token (parser);
+	  if (tok->type != CPP_STRING)
+	    {
+	      c_parser_error (parser, "expected string");
+	      c_parser_skip_to_end_of_block_or_statement (parser);
+	      return;
+	    }
+	  gcc_assert (TREE_CODE (tok->value) == STRING_CST);
+	  single_pass_name = TREE_STRING_POINTER (tok->value);
+	  c_parser_consume_token (parser);
+
+	  c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+	}
+    }
+
   finish_declspecs (specs);
   bool auto_type_p = specs->typespec_word == cts_auto_type;
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
@@ -2146,7 +2190,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
         tv = TV_PARSE_INLINE;
       else
         tv = TV_PARSE_FUNC;
-      timevar_push (tv);
+      auto_timevar at (g_timer, tv);
 
       /* Parse old-style parameter declarations.  ??? Attributes are
 	 not allowed to start declaration specifiers here because of a
@@ -2173,6 +2217,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
 	= c_parser_peek_token (parser)->location;
+
+      /* If we had an rtl-body-specifier, use the RTL parser now,
+	 consuming the function body.  */
+      if (rtl_body_p)
+	{
+	  c_parser_parse_rtl_body (parser, single_pass_name);
+	  return;
+	}
+
       fnbody = c_parser_compound_statement (parser);
       if (flag_cilkplus && contains_array_notation_expr (fnbody))
 	fnbody = expand_array_notation_exprs (fnbody);
@@ -2195,7 +2248,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	  finish_function ();
 	}
 
-      timevar_pop (tv);
       break;
     }
 }
@@ -18313,4 +18365,61 @@ c_parser_array_notation (location_t loc, c_parser *parser, tree initial_index,
   return value_tree;
 }
 
+/* Parse the body of a function declaration marked with "__RTL".
+
+   The RTL parser works on the level of characters read from a
+   FILE *, whereas c_parser works at the level of tokens.
+   Square this circle by consuming all of the tokens up to and
+   including the closing brace, recording the start/end of the RTL
+   fragment, and reopening the file and re-reading the relevant
+   lines within the RTL parser.
+
+   This requires the opening and closing braces of the C function
+   to be on separate lines from the RTL they wrap.  */
+
+void
+c_parser_parse_rtl_body (c_parser *parser, const char *single_pass_name)
+{
+  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    return;
+
+  location_t start_loc = c_parser_peek_token (parser)->location;
+
+  /* Consume all tokens, up to the closing brace, handling
+     matching pairs of braces in the rtl dump.  */
+  int num_open_braces = 1;
+  while (1)
+    {
+      switch (c_parser_peek_token (parser)->type)
+	{
+	case CPP_OPEN_BRACE:
+	  num_open_braces++;
+	  break;
+	case CPP_CLOSE_BRACE:
+	  if (--num_open_braces == 0)
+	    goto found_closing_brace;
+	  break;
+	default:
+	  break;
+	}
+      c_parser_consume_token (parser);
+    }
+
+ found_closing_brace:
+  /* At the closing brace; record its location.  */
+  location_t end_loc = c_parser_peek_token (parser)->location;
+
+  /* Consume the closing brace.  */
+  c_parser_consume_token (parser);
+
+  /* Invoke the RTL parser.  */
+  if (!read_rtl_function_body_from_file_range (start_loc, end_loc))
+    return;
+
+ /*  If -fsingle-pass=PASS_NAME was provided, locate and run PASS_NAME
+      on cfun, as created above.  */
+  if (single_pass_name)
+    run_one_rtl_pass_by_name (single_pass_name);
+}
+
 #include "gt-c-c-parser.h"
diff --git a/gcc/read-md.c b/gcc/read-md.c
index be55777..e713466 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -419,6 +419,16 @@ base_rtx_reader::read_char (void)
   else
     m_read_md_colno++;
 
+  /* If we're filtering lines, treat everything outside the
+     range of interest as a space.  */
+  if (m_first_line && m_last_line)
+    {
+      if (m_read_md_lineno < m_first_line)
+	return ' ';
+      if (m_read_md_lineno > m_last_line)
+	return EOF;
+    }
+
   return ch;
 }
 
@@ -1000,7 +1010,9 @@ base_rtx_reader::base_rtx_reader ()
   m_read_md_lineno (0),
   m_read_md_colno (0),
   m_first_dir_md_include (NULL),
-  m_last_dir_md_include_ptr (&m_first_dir_md_include)
+  m_last_dir_md_include_ptr (&m_first_dir_md_include),
+  m_first_line (0),
+  m_last_line (0)
 {
   /* Set the global singleton pointer.  */
   base_rtx_reader_ptr = this;
@@ -1307,6 +1319,26 @@ base_rtx_reader::read_md_files (int argc, const char **argv,
   return !have_error;
 }
 
+/* Read FILENAME, filtering to just the given lines.  */
+
+bool
+base_rtx_reader::read_file_fragment (const char *filename,
+				     int first_line,
+				     int last_line)
+{
+  m_read_md_filename = filename;
+  m_read_md_file = fopen (m_read_md_filename, "r");
+  if (m_read_md_file == 0)
+    {
+      perror (m_read_md_filename);
+      return false;
+    }
+  m_first_line = first_line;
+  m_last_line = last_line;
+  handle_toplevel_file ();
+  return !have_error;
+}
+
 /* class noop_reader : public base_rtx_reader */
 
 /* A dummy implementation which skips unknown directives.  */
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 4933912..2058002 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -98,6 +98,9 @@ class base_rtx_reader
   virtual ~base_rtx_reader ();
 
   bool read_md_files (int, const char **, bool (*) (const char *));
+  bool read_file_fragment (const char *filename,
+			   int first_line,
+			   int last_line);
 
   /* A hook that handles a single .md-file directive, up to but not
      including the closing ')'.  It takes two arguments: the file position
@@ -159,6 +162,10 @@ class base_rtx_reader
 
   /* A pointer to the null terminator of the md include chain.  */
   file_name_list **m_last_dir_md_include_ptr;
+
+  /* If non-zero, filter the input to just this subset of lines.  */
+  int m_first_line;
+  int m_last_line;
 };
 
 /* Global singleton; constrast with rtx_reader_ptr below.  */
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
index 0723585..73493ec 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -593,23 +593,31 @@ function_reader::create_function ()
   else
     rtl_register_cfg_hooks ();
 
-  /* Create cfun.  */
-  tree fn_name = get_identifier (m_name ? m_name : "test_1");
-  tree int_type = integer_type_node;
-  tree return_type = int_type;
-  tree arg_types[3] = {int_type, int_type, int_type};
-  tree fn_type = build_function_type_array (return_type, 3, arg_types);
-  tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
-				 fn_type);
-  tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
-			     return_type);
-  DECL_ARTIFICIAL (resdecl) = 1;
-  DECL_IGNORED_P (resdecl) = 1;
-  DECL_RESULT (fndecl) = resdecl;
-  allocate_struct_function (fndecl, false);
-  /* This sets cfun.  */
-
-  current_function_decl = fndecl;
+  /* When run from selftests or "rtl1", cfun is NULL.
+     When run from "cc1" for a C function tagged with __RTL, cfun is the
+     tagged function.  */
+  if (!cfun)
+    {
+      tree fn_name = get_identifier (m_name ? m_name : "test_1");
+      tree int_type = integer_type_node;
+      tree return_type = int_type;
+      tree arg_types[3] = {int_type, int_type, int_type};
+      tree fn_type = build_function_type_array (return_type, 3, arg_types);
+      tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+				     fn_type);
+      tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+				 return_type);
+      DECL_ARTIFICIAL (resdecl) = 1;
+      DECL_IGNORED_P (resdecl) = 1;
+      DECL_RESULT (fndecl) = resdecl;
+      allocate_struct_function (fndecl, false);
+      /* This sets cfun.  */
+      current_function_decl = fndecl;
+    }
+
+  gcc_assert (cfun);
+  gcc_assert (current_function_decl);
+  tree fndecl = current_function_decl;
 
   cfun->curr_properties = (PROP_cfg | PROP_rtl);
 
@@ -1817,6 +1825,42 @@ read_rtl_function_body (int argc, const char **argv,
   return true;
 }
 
+/* Run the RTL dump parser on the range of lines between START_LOC and
+   END_LOC (including those lines).  */
+
+bool
+read_rtl_function_body_from_file_range (location_t start_loc,
+					location_t end_loc)
+{
+  expanded_location exploc_start = expand_location (start_loc);
+  expanded_location exploc_end = expand_location (end_loc);
+
+  if (exploc_start.file != exploc_end.file)
+    {
+      error_at (end_loc, "start/end of RTL fragment are in different files");
+      return false;
+    }
+  if (exploc_start.line >= exploc_end.line)
+    {
+      error_at (end_loc,
+		"start of RTL fragment must be on an earlier line than end");
+      return false;
+    }
+
+  in_rtl_frontend_p = true;
+
+  initialize_rtl ();
+  init_emit ();
+  init_varasm_status ();
+
+  function_reader reader (NULL);
+  if (!reader.read_file_fragment (exploc_start.file, exploc_start.line,
+				  exploc_end.line - 1))
+    return false;
+
+  return true;
+}
+
 #if CHECKING_P
 
 namespace selftest {
diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
index d26c797..c69d308 100644
--- a/gcc/read-rtl-function.h
+++ b/gcc/read-rtl-function.h
@@ -34,4 +34,7 @@ extern bool read_rtl_function_body (int argc, const char **argv,
 				    function_reader_policy *policy,
 				    int *out_pseudo_offset);
 
+extern bool read_rtl_function_body_from_file_range (location_t start_loc,
+						    location_t end_loc);
+
 #endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/testsuite/rtl.dg/rtl.exp b/gcc/testsuite/rtl.dg/rtl.exp
index 71bebb9..6c7c7f4 100644
--- a/gcc/testsuite/rtl.dg/rtl.exp
+++ b/gcc/testsuite/rtl.dg/rtl.exp
@@ -29,8 +29,10 @@ if ![info exists DEFAULT_RTLFLAGS] then {
 # Initialize `dg'.
 dg-init
 
-# Gather a list of all tests.
+# Gather a list of all tests: both .rtl tests for use with rtl1, and .c tests
+# for use with cc1.
 set tests [lsort [find $srcdir/$subdir *.rtl]]
+set tests [concat $tests [lsort [find $srcdir/$subdir *.c]]]
 
 verbose "rtl.exp tests: $tests" 1
 
diff --git a/gcc/testsuite/rtl.dg/x86_64/different-structs.c b/gcc/testsuite/rtl.dg/x86_64/different-structs.c
new file mode 100644
index 0000000..d5c0bed
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/different-structs.c
@@ -0,0 +1,101 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+extern double sqrt(double x);
+
+struct foo
+{
+  double x;
+  double y;
+};
+
+struct bar
+{
+  double x;
+  double y;
+};
+
+double __RTL test (struct foo *f, const struct bar *b)
+{
+#if 0
+  /* Result of "expand" on this C code, compiled for x86_64 with -Os.  */
+  f->x += b->x;
+  f->y += b->y;
+  return sqrt (f->x * f->x + f->y * f->y);
+#endif
+(function "test"
+  (insn-chain
+    (note 1 0 5 (nil) NOTE_INSN_DELETED)
+    (note 5 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+    (insn 2 5 3 2 (set (reg/v/f:DI 97 [ f ])
+                (reg:DI 5 di [ f ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:16 -1
+             (nil))
+    (insn 3 2 4 2 (set (reg/v/f:DI 98 [ b ])
+                (reg:DI 4 si [ b ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:16 -1
+             (nil))
+    (note 4 3 7 2 NOTE_INSN_FUNCTION_BEG)
+    (insn 7 4 8 2 (set (reg:DF 99)
+                (mem:DF (reg/v/f:DI 97 [ f ]) [2 f_11(D)->x+0 S8 A64])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
+             (nil))
+    (insn 8 7 9 2 (set (reg:DF 89 [ _3 ])
+                (plus:DF (reg:DF 99)
+                    (mem:DF (reg/v/f:DI 98 [ b ]) [2 b_12(D)->x+0 S8 A64]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
+             (nil))
+    (insn 9 8 10 2 (set (mem:DF (reg/v/f:DI 97 [ f ]) [2 f_11(D)->x+0 S8 A64])
+                (reg:DF 89 [ _3 ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
+             (nil))
+    (insn 10 9 11 2 (set (reg:DF 100)
+                (mem:DF (plus:DI (reg/v/f:DI 97 [ f ])
+                        (const_int 8 [0x8])) [2 f_11(D)->y+0 S8 A64])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
+             (nil))
+    (insn 11 10 12 2 (set (reg:DF 92 [ _6 ])
+                (plus:DF (reg:DF 100)
+                    (mem:DF (plus:DI (reg/v/f:DI 98 [ b ])
+                            (const_int 8 [0x8])) [2 b_12(D)->y+0 S8 A64]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
+             (nil))
+    (insn 12 11 13 2 (set (mem:DF (plus:DI (reg/v/f:DI 97 [ f ])
+                        (const_int 8 [0x8])) [2 f_11(D)->y+0 S8 A64])
+                (reg:DF 92 [ _6 ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
+             (nil))
+    (insn 13 12 14 2 (set (reg:DF 101)
+                (mult:DF (reg:DF 89 [ _3 ])
+                    (reg:DF 89 [ _3 ]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (insn 14 13 15 2 (set (reg:DF 102)
+                (mult:DF (reg:DF 92 [ _6 ])
+                    (reg:DF 92 [ _6 ]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (insn 15 14 16 2 (set (reg:DF 103)
+                (plus:DF (reg:DF 101)
+                    (reg:DF 102))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (insn 16 15 17 2 (set (reg:DF 21 xmm0)
+                (reg:DF 103)) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (call_insn/j 17 16 18 2 (set (reg:DF 21 xmm0)
+                (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
+                    (const_int 0 [0]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>)
+                (expr_list:REG_EH_REGION (const_int 0 [0])
+                    (nil)))
+            (expr_list:DF (use (reg:DF 21 xmm0))
+                (nil)))
+    (barrier 18 17 0)
+  ) ;; insn-chain
+  (cfg
+    (bb 0
+      (edge 0 2 (flags 0x1))
+    ) ;; bb
+    (bb 2
+      (edge 2 1 (flags 0x1002))
+    ) ;; bb
+    (bb 1
+    ) ;; bb
+  ) ;; cfg
+  (crtl
+    (return_rtx 
+      (reg/i:DF 21 xmm0)
+    ) ;; return_rtx
+  ) ;; crtl
+) ;; function "test"
+
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
new file mode 100644
index 0000000..11b6f24
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
@@ -0,0 +1,23 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+int __RTL test_returning_constant (void)
+{
+  /* C code:
+     return 42; */
+
+  (function "test_returning_constant"
+    (insn-chain
+      (note 1 0 3 (nil) NOTE_INSN_DELETED)
+      (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+      (insn 5 2 9 2 (set (reg:SI 87 [ <retval> ])
+	    (const_int 42 [0x2a])) test-return-const.c:3 -1
+         (nil))
+      (insn 9 5 10 2 (set (reg/i:SI 0 ax)
+	      (reg:SI 87 [ <retval> ])) test-return-const.c:4 -1
+         (nil))
+      (insn 10 9 0 2 (use (reg/i:SI 0 ax)) test-return-const.c:4 -1
+         (nil))
+     ) ;; insn-chain
+   );; function
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
new file mode 100644
index 0000000..83594b3
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
@@ -0,0 +1,27 @@
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-fwprop1" } */
+
+int __RTL ("rtl-fwprop1") test_returning_constant (void)
+{
+  /* C code:
+     return 42; */
+  (function "test"
+    (insn-chain
+      (note 3 0 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+      (insn 5 2 9 2 (set (reg:SI 87 [ <retval> ])
+        (const_int 42 [0x2a])) test-return-const.c:3 82 {*movsi_internal}
+        (nil))
+      (insn 9 5 10 2 (set (reg/i:SI 0 ax)
+	(const_int 42 [0x2a])) test-return-const.c:4 82 {*movsi_internal}
+        (expr_list:REG_DEAD (reg:SI 87 [ <retval> ])
+	 (nil)))
+      (insn 10 9 0 2 (use (reg/i:SI 0 ax)) test-return-const.c:4 -1
+       (nil))
+    ) ;; insn-chain
+  ) ;; function
+}
+
+/* Verify that insn 5 is eliminated.  */
+/* { dg-final { scan-rtl-dump "deferring deletion of insn with uid = 5" "fwprop1" } } */
+/* { dg-final { scan-rtl-dump "Deleted 1 trivially dead insns" "fwprop1" } } */
diff --git a/gcc/testsuite/rtl.dg/x86_64/test-rtl.c b/gcc/testsuite/rtl.dg/x86_64/test-rtl.c
new file mode 100644
index 0000000..0ffeab7
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/test-rtl.c
@@ -0,0 +1,95 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+/* Test of embedding RTL dump in a C function, tagged with "__RTL".
+
+   This is a dump of test.c from immediately after "expand", for x86_64.  */
+
+int __RTL test_1 (int i, int j, int k)
+{
+  /*
+    if (i < j)
+      return k + 4;
+    else
+      return -k;
+  */
+  (function "test_1"
+   (insn-chain
+  (note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 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 ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 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])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 4 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 14 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 14 13 15 4 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 15 14 16)
+(code_label 16 15 17 5 2 (nil) [1 uses])
+(note 17 16 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 5 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 5 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 6 3 (nil) [1 uses])
+(note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 6 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 6 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+
+    ) ;; insn-chain
+   ) ;; function
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c b/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
new file mode 100644
index 0000000..8536bf4
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
@@ -0,0 +1,40 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+int __RTL times_two (int i)
+{
+  /* C function:
+     return i * 2;  */
+  (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 ])) times-two.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])) times-two.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))
+        ]) times-two.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 ])) times-two.c:3 -1
+     (nil))
+  (insn 14 10 15 2 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) times-two.c:4 -1
+     (nil))
+  (insn 15 14 0 2 (use (reg/i:SI 0 ax)) times-two.c:4 -1
+     (nil))
+    ) ;; insn-chain
+  ) ;; function
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c b/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
new file mode 100644
index 0000000..b4d20a7
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
@@ -0,0 +1,57 @@
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-dfinit" } */
+
+int __RTL ("rtl-dfinit") times_two (int i)
+{
+  /* C function:
+     return i * 2;  */
+ (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 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) times-two.c:2 82 {*movsi_internal}
+     (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 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) times-two.c:3 82 {*movsi_internal}
+     (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))
+        ]) times-two.c:3 529 {*ashlsi3_1}
+     (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (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 ])) times-two.c:3 82 {*movsi_internal}
+     (nil))
+   (insn 14 10 15 2 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) times-two.c:4 82 {*movsi_internal}
+     (nil))
+   (insn 15 14 0 2 (use (reg/i:SI 0 ax)) times-two.c:4 -1
+     (nil))
+   ) ;; insn-chain
+
+   (crtl
+     (return_rtx
+       (reg/i:SI 0 ax)
+     ) ;; return_rtx
+   ) ;; crtl
+  ) ;; function
+}
+
+/* Verify that the dataflow information matches what cc1 would have
+   generated.  In particular, in earlier versions of the RTL
+   frontend, the exit block use of reg 0 (ax) wasn't picked up
+   on, due to not setting up crtl->return_rtx based on
+   DECL_RESULT (fndecl).  */
+
+/* { dg-final { scan-rtl-dump ";;  exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+
+/* { dg-final { scan-rtl-dump ";;  regs ever live.*0 .ax. 5 .di. 17 .flags." "dfinit" } } */
-- 
1.8.5.3

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

* [PATCH] RTL frontend (rtl1), on top of dump reader (v4)
  2016-10-06 15:24   ` [PATCH 15/16] RTL frontend (rtl1), on top of dump reader Bernd Schmidt
@ 2016-10-07 16:22     ` David Malcolm
  0 siblings, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-07 16:22 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm

On Thu, 2016-10-06 at 17:23 +0200, Bernd Schmidt wrote:
> Let me just make a first pass over this for minor/obvious issues.
>
> > +we have little control of the input to that specific pass.  We
>
> "control over" maybe?

Fixed.

> > +The testsuite is below @file{gcc/testsuite/rtl.dg}.
>
> Not sure this needs to be in the manual (I have similar doubts about
> the
> entire motivation section, but I guess we can keep it).

This is within the "internals" part of the manual; presumably the
audience for that manual is gcc developers.

> Also, "below"?

Changed to "within".

> > +/* rtl-error.c - Replacement for errors.c for use by RTL frontend
> > +   Copyright (C) 2016 Free Software Foundation, Inc.
>
> Why have this and not use the normal machinery?

(see https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00489.html for
discussion of that).

> > +
> > +static bool
> > +rtl_langhook_handle_option (
> > +    size_t scode,
> > +    const char *arg,
> > +    int value ATTRIBUTE_UNUSED,
> > +    int kind ATTRIBUTE_UNUSED,
> > +    location_t loc ATTRIBUTE_UNUSED,
> > +    const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
>
> Please line up the arguments, including the first, with the open
> paren.

Fixed.

> For hooks I think we're converging towards just not naming unused
> args.

I removed the names (and ATTRIBUTE_UNUSED).

> > +
> > +  /*  If -fsingle-pass=PASS_NAME was provided, locate and run
> > PASS_NAME
> > +      on cfun, as created above.  */
>
> Comment text indented too much.

Fixed.

> > +/* Implementation of LANG_HOOKS_TYPE_FOR_MODE, taken from Go
> > frontend.  */
> > +
> > +static tree
> > +rtl_langhook_type_for_mode (machine_mode mode, int unsignedp)
> > +{
> > +  tree type;
> > +  /* Go has no vector types.  Build them here.  FIXME: It does not
> > +     make sense for the middle-end to ask the frontend for a type
> > +     which the frontend does not support.  However, at least for
> > now
> > +     it is required.  See PR 46805.  */
>
> Hmm, not sure it makes much sense to have comments referencing Go.

Heh.  Can you spot which frontend I used as a model? :)

> > +  if (VECTOR_MODE_P (mode))
> > +    {
> > +      tree inner;
> > +
> > +      inner = rtl_langhook_type_for_mode (GET_MODE_INNER (mode),
> > unsignedp);
> > +      if (inner != NULL_TREE)
> > +	return build_vector_type_for_mode (inner, mode);
> > +      return NULL_TREE;
> > +    }
> > +
> > +  // FIXME: This static_cast should be in machmode.h.
> > +  enum mode_class mc = static_cast<enum
> > mode_class>(GET_MODE_CLASS(mode));
> > +  if (mc == MODE_INT)
> > +    return rtl_langhook_type_for_size(GET_MODE_BITSIZE(mode),
> > unsignedp);
>
> Also not really following our coding standards. Presumably this is
> all
> copied?

Yes, from Go.  I've fixed things up in the next version of the patch,
and I'll work on a patch for Go to fix them up there.

> > +#include <mpfr.h>
>
> The include list probably wants checking whether everything is really
> necessary; this one stood out as a bit odd (several files).

This was for the:

  /* The default precision for floating point numbers.  This is used
     for floating point constants with abstract type.  This may
     eventually be controllable by a command line option.  */
  mpfr_set_default_prec (256);

call in rtl_langhook_init, again copied from Go.  I can drop it.

I went through the list of includes; doing so revealed that this code
within rtl_langhook_parse_file:

  in_rtl_frontend_p = true;

  initialize_rtl ();
  init_emit ();
  init_varasm_status ();

was redundant (we were also doing it in read_rtl_function_body; this
code has gone through a *lot* of refactoring).

So I've trimmed things quite a bit in rtl-frontend.c.

When trimming the headers, I was able to eliminate rtl.h from the deps,
so I was able to remove:

 /* Front ends normally should never have to include RTL headers.
    This is enforced in system.h by poisoning various header double-include
    protection defines.
    However, for obvious reasons, the RTL frontend needs RTL headers.
    Override this protection for this special case.  */
 #undef IN_GCC_FRONTEND

> > +
> > +#ifndef GCC_RUN_ONE_RTL_PASS_H
> > +#define GCC_RUN_ONE_RTL_PASS_H
> > +
> > +extern void run_one_rtl_pass_by_name (const char *pass_name);
> > +
> > +#endif /* GCC_RUN_ONE_RTL_PASS_H */
>
> Do we really need an entire header file for a single declaration?

The problem I kept running into was that system.h has this:

/* Front ends should never have to include middle-end headers.  Enforce
   this by poisoning the header double-include protection defines.  */

run_one_rtl_pass_by_name gets used by both the RTL frontend in this
patch, and by cc1 in the followup __RTL patch (from c-parser.c), so
whatever header it's in, it needs to be one that can be included by
these frontend files with no rtl.h poisoning.  This seems like a
special-case, so it seemed to make sense to give it its own header.
Is there a better place for it?  Maybe pass_manager.h?

Updated patch follows...

gcc/ChangeLog:
	* Makefile.in (OBJS): Add run-one-rtl-pass.o.
	* doc/rtl-frontend.texi: New file.
	* doc/rtl.texi (RTL Representation): Add "RTL Frontend" to menu.
	Include rtl-frontend.texi.
	* gcc.c (default_compilers): Add a ".rtl" entry.
	* read-rtl-function.c (read_rtl_function_body): Set
	in_rtl_frontend_p.
	* rtl.c (in_rtl_frontend_p): New global.
	* rtl.h (in_rtl_frontend_p): New global decl.
	* run-one-rtl-pass.c: New file.
	* run-one-rtl-pass.h: New file.
	* toplev.c (compile_file): Bail out after the parse_file
	langhook if within the RTL frontend.

gcc/rtl/ChangeLog:
	* ChangeLog: New file.
	* Make-lang.in: New file.
	* config-lang.in: New file.
	* lang-specs.h: New file.
	* lang.opt: New file.
	* rtl-errors.c: New file.
	* rtl-frontend.c: New file.

gcc/testsuite/ChangeLog:
	* lib/rtl-dg.exp: New file.
	* rtl.dg/aarch64/asr_div1.rtl: New file.
	* rtl.dg/aarch64/pr71779.rtl: New file.
	* rtl.dg/cfg-extra-bb.rtl: New file.
	* rtl.dg/cfg-missing-bb.rtl: New file.
	* rtl.dg/good-include.rtl: New file.
	* rtl.dg/good-includee.md: New file.
	* rtl.dg/missing-include.rtl: New file.
	* rtl.dg/more-than-one-cfg.rtl: New file.
	* rtl.dg/rtl.exp: New file.
	* rtl.dg/test.c: New file.
	* rtl.dg/unknown-insn-uid.rtl: New file.
	* rtl.dg/unknown-rtx-code.rtl: New file.
	* rtl.dg/x86_64/dfinit.rtl: New file.
	* rtl.dg/x86_64/final.rtl: New file.
	* rtl.dg/x86_64/into-cfglayout.rtl: New file.
	* rtl.dg/x86_64/ira.rtl: New file.
	* rtl.dg/x86_64/pro_and_epilogue.rtl: New file.
	* rtl.dg/x86_64/vregs.rtl: New file.
---
 gcc/Makefile.in                                  |   1 +
 gcc/doc/rtl-frontend.texi                        | 262 ++++++++++++++++++
 gcc/doc/rtl.texi                                 |   3 +
 gcc/gcc.c                                        |   1 +
 gcc/read-rtl-function.c                          |   2 +
 gcc/rtl.c                                        |   2 +
 gcc/rtl.h                                        |   1 +
 gcc/rtl/Make-lang.in                             |  88 ++++++
 gcc/rtl/config-lang.in                           |  36 +++
 gcc/rtl/lang-specs.h                             |  25 ++
 gcc/rtl/lang.opt                                 |  33 +++
 gcc/rtl/rtl-errors.c                             |  34 +++
 gcc/rtl/rtl-frontend.c                           | 336 +++++++++++++++++++++++
 gcc/run-one-rtl-pass.c                           | 119 ++++++++
 gcc/run-one-rtl-pass.h                           |  25 ++
 gcc/testsuite/lib/rtl-dg.exp                     |  64 +++++
 gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl        |  32 +++
 gcc/testsuite/rtl.dg/aarch64/pr71779.rtl         |  44 +++
 gcc/testsuite/rtl.dg/cfg-extra-bb.rtl            |  12 +
 gcc/testsuite/rtl.dg/cfg-missing-bb.rtl          |  16 ++
 gcc/testsuite/rtl.dg/good-include.rtl            |   6 +
 gcc/testsuite/rtl.dg/good-includee.md            |   5 +
 gcc/testsuite/rtl.dg/missing-include.rtl         |   1 +
 gcc/testsuite/rtl.dg/more-than-one-cfg.rtl       |   7 +
 gcc/testsuite/rtl.dg/rtl.exp                     |  41 +++
 gcc/testsuite/rtl.dg/test.c                      |  31 +++
 gcc/testsuite/rtl.dg/unknown-insn-uid.rtl        |   6 +
 gcc/testsuite/rtl.dg/unknown-rtx-code.rtl        |   5 +
 gcc/testsuite/rtl.dg/x86_64/dfinit.rtl           | 102 +++++++
 gcc/testsuite/rtl.dg/x86_64/final.rtl            |  58 ++++
 gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl   |  91 ++++++
 gcc/testsuite/rtl.dg/x86_64/ira.rtl              |  91 ++++++
 gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl |  44 +++
 gcc/testsuite/rtl.dg/x86_64/vregs.rtl            |  88 ++++++
 gcc/toplev.c                                     |   7 +
 35 files changed, 1719 insertions(+)
 create mode 100644 gcc/doc/rtl-frontend.texi
 create mode 100644 gcc/rtl/Make-lang.in
 create mode 100644 gcc/rtl/config-lang.in
 create mode 100644 gcc/rtl/lang-specs.h
 create mode 100644 gcc/rtl/lang.opt
 create mode 100644 gcc/rtl/rtl-errors.c
 create mode 100644 gcc/rtl/rtl-frontend.c
 create mode 100644 gcc/run-one-rtl-pass.c
 create mode 100644 gcc/run-one-rtl-pass.h
 create mode 100644 gcc/testsuite/lib/rtl-dg.exp
 create mode 100644 gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl
 create mode 100644 gcc/testsuite/rtl.dg/aarch64/pr71779.rtl
 create mode 100644 gcc/testsuite/rtl.dg/cfg-extra-bb.rtl
 create mode 100644 gcc/testsuite/rtl.dg/cfg-missing-bb.rtl
 create mode 100644 gcc/testsuite/rtl.dg/good-include.rtl
 create mode 100644 gcc/testsuite/rtl.dg/good-includee.md
 create mode 100644 gcc/testsuite/rtl.dg/missing-include.rtl
 create mode 100644 gcc/testsuite/rtl.dg/more-than-one-cfg.rtl
 create mode 100644 gcc/testsuite/rtl.dg/rtl.exp
 create mode 100644 gcc/testsuite/rtl.dg/test.c
 create mode 100644 gcc/testsuite/rtl.dg/unknown-insn-uid.rtl
 create mode 100644 gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/dfinit.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/final.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/ira.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/vregs.rtl

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2147aee..c6f86db 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1432,6 +1432,7 @@ OBJS = \
 	rtlhash.o \
 	rtlanal.o \
 	rtlhooks.o \
+	run-one-rtl-pass.o \
 	sbitmap.o \
 	sched-deps.o \
 	sched-ebb.o \
diff --git a/gcc/doc/rtl-frontend.texi b/gcc/doc/rtl-frontend.texi
new file mode 100644
index 0000000..393630d
--- /dev/null
+++ b/gcc/doc/rtl-frontend.texi
@@ -0,0 +1,262 @@
+@node RTL Frontend
+@section RTL Frontend
+
+@subsection Purpose
+
+Historically GCC testing has been done by providing source files
+to be built with various command-line options (via DejaGnu
+directives), dumping state at pertinent places, and verifying
+properties of the state via these dumps.
+
+A strength of this approach is that we have excellent integration
+testing, as every test case exercises the toolchain as a whole, but
+it has the drawback that when testing a specific pass,
+we have little control over the input to that specific pass.  We
+provide input, and the various passes transform the state
+of the internal representation:
+
+@smallexample
+  INPUT -> PASS-1 -> STATE-1 -> PASS-2 -> STATE-2 -> ...
+    -> etc ->
+    -> ... -> PASS-n-1 -> STATE-n-1 -> PASS-n -> STATE-n
+                          ^            ^         ^
+                          |            |         Output from the pass
+                          |            The pass we care about
+                          The actual input to the pass
+@end smallexample
+
+so the intervening passes before "PASS-n" could make changes to the
+IR that affect the input seen by our pass ("STATE-n-1" above).  This
+can break our test cases, sometimes in a form that's visible,
+sometimes invisibly (e.g. where a test case silently stops providing
+coverage).
+
+The aim of the RTL frontend is to provide a convenient way to test
+individual passes in the backend, by loading dumps of specific RTL
+state (possibly edited by hand), and then running just one specific
+pass on them, so that we effectively have this:
+
+@smallexample
+  INPUT -> PASS-n -> OUTPUT
+@end smallexample
+
+thus fixing the problem above.
+
+The goal is to make it easy to write more fine-grained and
+robust test coverage for the RTL phase of GCC.  However this should be
+seen as @emph{complementary} to the existing "integrated testing" approach:
+patches should include both RTL frontend tests @emph{and} integrated tests,
+to avoid regressing the great integration testing we currently have.
+
+The idea is to use the existing dump format as a input format, since
+presumably existing GCC developers are very familiar with the dump
+format.
+
+One other potential benefit of this approach is to allow unit-testing
+of machine descriptions - we could provide specific RTL fragments,
+and have the @file{rtl.dg} testsuite directly verify that we recognize all
+instructions and addressing modes that a given target ought to support.
+
+@subsection Structure
+
+The RTL frontend is similar to a regular frontend: a @file{gcc/rtl}
+subdirectory within the source tree contains frontend-specific hooks.
+These provide a new @code{rtl} frontend, which can be optionally
+enabled at configuration time within @option{--enable-languages}.
+
+If enabled, it builds an @command{rtl1} binary, which is invoked by the
+@command{gcc} driver on files with a @file{.rtl} extension.
+
+The testsuite is within @file{gcc/testsuite/rtl.dg}.
+
+@subsection Input format
+
+Input files should have a @file{.rtl} extension.
+
+The parser accepts the format emitted by @code{print_rtx_function}:
+
+@smallexample
+(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"
+@end smallexample
+
+To make it easier to hand-edit file, the @code{(cfg)} and @code{(crtl)}
+directives can be omitted.  If the @code{(cfg)} directive is omitted,
+then the parser frontend reconstructs the edges implied by jump
+instructions.  This ought to work OK for ``cfgrtl'' mode, but isn't
+going to work for ``cfglayout'' mode - in the latter, unconditional jumps
+are represented purely by edges in the CFG, and so this information must
+be provided by a @code{(cfg)} directive.  See
+@uref{https://gcc.gnu.org/wiki/cfglayout_mode} for more information
+on ``cfgrtl'' mode vs ``cfglayout mode''.
+
+@subsection Register numbers
+
+print_rtx will print a name for hard and virtual registers
+after the register number, and no name for pseudos.
+
+The parser looks for a name after the number.  If there is, such as:
+
+@smallexample
+  (reg/f:DI 82 virtual-stack-vars)
+@end smallexample
+
+it assumes a hard or virtual reg, and tries to parse the name:
+
+@itemize @bullet
+
+@item
+if the name is recognized, it uses the target's current number for that
+name (future-proofing virtuals against @file{.md} changes)
+
+@item
+if the name is not recognized, issue a fatal error (it's probably a
+typo, or maybe a backport from a future version of gcc, or a target
+incompatibility)
+
+@item
+if there's no name, it assumes it's a pseudo.  If any such the registers
+appear in the dump with a register number <= @code{LAST_VIRTUAL_REGISTER},
+then all such pseudos have their register number adjusted by an offset so
+that all are > @code{LAST_VIRTUAL_REGISTER}, to future-proof against
+@file{.md} changes, and to allow some measure of target-independence.
+Otherwise, the numbering is left untouched (the common case).
+
+@end itemize
+
+
+@subsection Limitations
+
+@itemize @bullet
+
+@item
+It's a work-in-progress.  There will be bugs.
+
+
+@item
+The existing RTL code is structured around a single function being
+optimized, so, as a simplification, the RTL frontend can only handle
+one function per input file.
+
+@item
+The RTL frontend doesn't have any knowledge of parameters, types,
+locals, globals, etc.  It creates a single function.
+The function is currently hardcoded to have this signature:
+
+     int NAME (int, int, int);
+
+since there's no syntax for specify otherwise, and we need to provide
+a @code{FUNCTION_DECL} tree when building a function object (by calling
+@code{allocate_struct_function}).
+
+@item
+Similarly, there are no types beyond the built-in ones; all expressions
+are treated as being of type @code{int}.  I suspect that this approach
+will be too simplistic when it comes to e.g. aliasing.
+
+@item
+There's no support for running more than one pass; fixing this would
+require being able to run passes from a certain point onwards.
+
+@item
+Roundtripping of recognized instructions may be an issue (i.e. those
+with @code{INSN_CODE} != -1), such as the ``667 @{jump@}'' in the
+following:
+
+@smallexample
+    (jump_insn 50 49 51 10
+      (set (pc)
+           (label_ref:DI 59)) ../../src/test-switch.c:18 667 @{jump@}
+           (nil) -> 59)
+@end smallexample
+
+since the integer ID can change when the @file{.md} files are changed
+(and the associated pattern name is very much target-specific).
+Currently the loaded ignores them, resetting the @code{INSN_CODE} to -1.
+An alternative strategy would be to lookup the insn by name, and
+use the correct @code{INSN_CODE} (future-proofing against @file{.md}
+changes, but making dumps more target-specific).
+
+@end itemize
+
+@subsection TODO items
+
+@itemize @bullet
+
+@item
+test with other architectures
+
+@item
+example with "-g"
+
+@item
+implement a fuzzer (or use AFL on the existing test cases)
+
+@end itemize
+
+@subsection Cross-arch issues
+
+Test cases are likely to be target-specific.  Examples include:
+
+@itemize @bullet
+
+@item
+unknown modes e.g. this from x86_64:
+
+@smallexample
+    (reg:CCGC 17 flags)
+@end smallexample
+
+fails on aarch64 due to the lack of a "CCGC" mode.
+
+@end itemize
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 692d9b5..9e86df9 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -41,6 +41,7 @@ form uses nested parentheses to indicate the pointers in the internal form.
 * Calls::             RTL representation of function call insns.
 * Sharing::           Some expressions are unique; others *must* be copied.
 * Reading RTL::       Reading textual RTL from a file.
+* RTL Frontend::      Testing GCC using RTL dumps.
 @end menu
 
 @node RTL Objects
@@ -4236,3 +4237,5 @@ The proper way to interface GCC to a new language front end is with
 the ``tree'' data structure, described in the files @file{tree.h} and
 @file{tree.def}.  The documentation for this structure (@pxref{GENERIC})
 is incomplete.
+
+@include rtl-frontend.texi
diff --git a/gcc/gcc.c b/gcc/gcc.c
index fd2b182..7a21a74 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1296,6 +1296,7 @@ static const struct compiler default_compilers[] =
   {".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0},
   {".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0},
   {".go", "#Go", 0, 1, 0},
+  {".rtl", "#RTL", 0, 1, 0},
   /* Next come the entries for C.  */
   {".c", "@c", 0, 0, 1},
   {"@c",
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
index 0cd34d4..0723585 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -1801,6 +1801,8 @@ read_rtl_function_body (int argc, const char **argv,
 			function_reader_policy *policy,
 			int *out_pseudo_offset)
 {
+  in_rtl_frontend_p = true;
+
   initialize_rtl ();
   init_emit ();
   init_varasm_status ();
diff --git a/gcc/rtl.c b/gcc/rtl.c
index a445cdc..9729c82 100644
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -878,3 +878,5 @@ rtl_check_failed_flag (const char *name, const_rtx r, const char *file,
      name, GET_RTX_NAME (GET_CODE (r)), func, trim_filename (file), line);
 }
 #endif /* ENABLE_RTL_FLAG_CHECKING */
+
+bool in_rtl_frontend_p = false;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 0741fc6..813d7a9 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3748,5 +3748,6 @@ struct GTY(()) cgraph_rtl_info {
   unsigned function_used_regs_valid: 1;
 };
 
+extern bool in_rtl_frontend_p;
 
 #endif /* ! GCC_RTL_H */
diff --git a/gcc/rtl/Make-lang.in b/gcc/rtl/Make-lang.in
new file mode 100644
index 0000000..74d0a3e
--- /dev/null
+++ b/gcc/rtl/Make-lang.in
@@ -0,0 +1,88 @@
+# Make-lang.in -- Top level -*- makefile -*- fragment for RTL frontend.
+
+# 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/>.
+
+# This file provides the language dependent support in the main Makefile.
+
+# The name for selecting the RTL frontend in LANGUAGES.
+rtl: rtl1$(exeext)
+
+.PHONY: rtl
+
+# Use strict warnings.
+rtl-warn = $(STRICT_WARN)
+
+rtl_OBJS = \
+	rtl/rtl-errors.o \
+	rtl/rtl-frontend.o
+
+rtl1$(exeext): $(rtl_OBJS) attribs.o $(BACKEND) $(LIBDEPS)
+	+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+	      $(rtl_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS)
+
+# Build hooks:
+
+rtl.all.cross:
+rtl.start.encap:
+rtl.rest.encap:
+rtl.info:
+rtl.dvi:
+rtl.html:
+rtl.pdf:
+rtl.man:
+
+lang_checks += check-rtl
+lang_checks_parallelized += check-rtl
+check_rtl_parallelize = 10
+
+# Install hooks.
+
+rtl.install-common:
+rtl.install-man:
+rtl.install-plugin:
+rtl.install-info:
+rtl.install-pdf:
+rtl.install-html:
+rtl.uninstall:
+
+# Clean hooks.
+
+rtl.mostlyclean:
+	-rm -f rtl1$(exeext)
+	-rm -f rtl/*$(objext)
+	-rm -f rtl/*$(coverageexts)
+rtl.clean:
+rtl.distclean:
+	-rm -f rtl/config.status rtl/Makefile
+rtl.maintainer-clean:
+
+# Stage hooks.
+
+rtl.stage1: stage1-start
+	-mv rtl/*$(objext) stage1/rtl
+rtl.stage2: stage2-start
+	-mv rtl/*$(objext) stage2/rtl
+rtl.stage3: stage3-start
+	-mv rtl/*$(objext) stage3/rtl
+rtl.stage4: stage4-start
+	-mv rtl/*$(objext) stage4/rtl
+rtl.stageprofile: stageprofile-start
+	-mv rtl/*$(objext) stageprofile/rtl
+rtl.stagefeedback: stagefeedback-start
+	-mv rtl/*$(objext) stagefeedback/rtl
diff --git a/gcc/rtl/config-lang.in b/gcc/rtl/config-lang.in
new file mode 100644
index 0000000..3b101ce
--- /dev/null
+++ b/gcc/rtl/config-lang.in
@@ -0,0 +1,36 @@
+# config-lang.in -- Top level configure fragment for RTL frontend.
+
+# 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/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language	- name of language as it would appear in $(LANGUAGES)
+# compilers	- value to add to $(COMPILERS)
+
+language="rtl"
+
+compilers="rtl1\$(exeext)"
+
+target_libs=""
+
+gtfiles="\$(srcdir)/rtl/rtl-frontend.c"
+
+# Do not build by default.
+build_by_default="no"
diff --git a/gcc/rtl/lang-specs.h b/gcc/rtl/lang-specs.h
new file mode 100644
index 0000000..2af33ab
--- /dev/null
+++ b/gcc/rtl/lang-specs.h
@@ -0,0 +1,25 @@
+/* lang-specs.h -- gcc driver specs for RTL frontend.
+   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/>.  */
+
+/* This is the contribution to the `default_compilers' array in gcc.c
+   for the RTL frontend.  */
+
+{".rtl",  "@RTL", 0, 1, 0},
+{"@RTL",  "rtl1 %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}",
+    0, 1, 0},
diff --git a/gcc/rtl/lang.opt b/gcc/rtl/lang.opt
new file mode 100644
index 0000000..2515ff3
--- /dev/null
+++ b/gcc/rtl/lang.opt
@@ -0,0 +1,33 @@
+; lang.opt -- Options for the gcc RTL front end.
+
+; 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/>.
+
+; See the GCC internals manual for a description of this file's format.
+
+; Please try to keep this file in ASCII collating order.
+
+Language
+RTL
+
+fsingle-pass=
+RTL Joined RejectNegative
+After loading the RTL input file, run the specified pass on it.
+
+
+; This comment is to ensure we retain the blank line above.
diff --git a/gcc/rtl/rtl-errors.c b/gcc/rtl/rtl-errors.c
new file mode 100644
index 0000000..1859cb6
--- /dev/null
+++ b/gcc/rtl/rtl-errors.c
@@ -0,0 +1,34 @@
+/* rtl-error.c - Replacement for errors.c for use by RTL frontend
+   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 "errors.h"
+
+/* Stub implementation of RTL error-handling for use by RTL frontend.  */
+
+void
+fatal (const char *, ...)
+{
+  abort ();
+}
+
+int have_error;
+
diff --git a/gcc/rtl/rtl-frontend.c b/gcc/rtl/rtl-frontend.c
new file mode 100644
index 0000000..9df8c0e
--- /dev/null
+++ b/gcc/rtl/rtl-frontend.c
@@ -0,0 +1,336 @@
+/* rtl-frontend.c - Top-level of RTL frontend
+   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 "target.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "debug.h"
+#include "convert.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "read-rtl-function.h"
+#include "run-one-rtl-pass.h"
+
+/* Language-dependent contents of a type.  */
+
+struct GTY(()) lang_type
+{
+  char dummy;
+};
+
+/* Language-dependent contents of a decl.  */
+
+struct GTY(()) lang_decl
+{
+  char dummy;
+};
+
+/* Language-dependent contents of an identifier.  This must include a
+   tree_identifier.  */
+
+struct GTY(()) lang_identifier
+{
+  struct tree_identifier common;
+};
+
+/* The resulting tree type.  */
+
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+	   chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+  union tree_node GTY((tag ("0"),
+		       desc ("tree_node_structure (&%h)"))) generic;
+  struct lang_identifier GTY((tag ("1"))) identifier;
+};
+
+/* We don't use language_function.  */
+
+struct GTY(()) language_function
+{
+  int dummy;
+};
+
+/* Language hooks.  */
+
+/* Implementation of LANG_HOOKS_INIT for the RTL frontend.  */
+
+static bool
+rtl_langhook_init (void)
+{
+  build_common_tree_nodes (false);
+
+  /* I don't know why this has to be done explicitly.  */
+  void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+  build_common_builtin_nodes ();
+
+  return true;
+}
+
+/* Implementation of LANG_HOOKS_OPTION_LANG_MASK for the RTL frontend.  */
+
+static unsigned int
+rtl_langhook_option_lang_mask (void)
+{
+  return CL_RTL;
+}
+
+/* The value of "-fsingle-pass=", if any.  */
+
+static const char *single_pass_name = NULL;
+
+/* Implementation of LANG_HOOKS_HANDLE_OPTION for the RTL frontend.  */
+
+static bool
+rtl_langhook_handle_option (size_t scode, const char *arg, int, int,
+			    location_t, const struct cl_option_handlers *)
+{
+  enum opt_code code = (enum opt_code) scode;
+
+  switch (code)
+    {
+    case OPT_fsingle_pass_:
+      single_pass_name =  xstrdup (arg);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+/* Implementation of LANG_HOOKS_PARSE_FILE for the RTL frontend.  */
+
+static void
+rtl_langhook_parse_file (void)
+{
+  auto_vec<const char *> argv (num_in_fnames + 1);
+  argv.safe_push (progname);
+  for (unsigned i = 0; i < num_in_fnames; i++)
+    argv.safe_push (in_fnames[i]);
+  if (!read_rtl_function_body (argv.length (), argv.address (), NULL, NULL,
+			       NULL))
+    return;
+
+  /* If -fsingle-pass=PASS_NAME was provided, locate and run PASS_NAME
+     on cfun, as created above.  */
+  if (single_pass_name)
+    run_one_rtl_pass_by_name (single_pass_name);
+}
+
+/* Implementation of LANG_HOOKS_TYPE_FOR_SIZE, taken from Go frontend.  */
+
+static tree
+rtl_langhook_type_for_size (unsigned int bits, int unsignedp)
+{
+  tree type;
+  if (unsignedp)
+    {
+      if (bits == INT_TYPE_SIZE)
+        type = unsigned_type_node;
+      else if (bits == CHAR_TYPE_SIZE)
+        type = unsigned_char_type_node;
+      else if (bits == SHORT_TYPE_SIZE)
+        type = short_unsigned_type_node;
+      else if (bits == LONG_TYPE_SIZE)
+        type = long_unsigned_type_node;
+      else if (bits == LONG_LONG_TYPE_SIZE)
+        type = long_long_unsigned_type_node;
+      else
+        type = make_unsigned_type(bits);
+    }
+  else
+    {
+      if (bits == INT_TYPE_SIZE)
+        type = integer_type_node;
+      else if (bits == CHAR_TYPE_SIZE)
+        type = signed_char_type_node;
+      else if (bits == SHORT_TYPE_SIZE)
+        type = short_integer_type_node;
+      else if (bits == LONG_TYPE_SIZE)
+        type = long_integer_type_node;
+      else if (bits == LONG_LONG_TYPE_SIZE)
+        type = long_long_integer_type_node;
+      else
+        type = make_signed_type(bits);
+    }
+  return type;
+}
+
+/* Implementation of LANG_HOOKS_TYPE_FOR_MODE, taken from Go frontend.  */
+
+static tree
+rtl_langhook_type_for_mode (machine_mode mode, int unsignedp)
+{
+  tree type;
+
+  enum mode_class mc = GET_MODE_CLASS (mode);
+  if (mc == MODE_INT)
+    return rtl_langhook_type_for_size (GET_MODE_BITSIZE (mode), unsignedp);
+  else if (mc == MODE_FLOAT)
+    {
+      switch (GET_MODE_BITSIZE (mode))
+	{
+	case 32:
+	  return float_type_node;
+	case 64:
+	  return double_type_node;
+	default:
+	  // We have to check for long double in order to support
+	  // i386 excess precision.
+	  if (mode == TYPE_MODE (long_double_type_node))
+	    return long_double_type_node;
+	}
+    }
+  else if (mc == MODE_COMPLEX_FLOAT)
+    {
+      switch (GET_MODE_BITSIZE (mode))
+	{
+	case 64:
+	  return complex_float_type_node;
+	case 128:
+	  return complex_double_type_node;
+	default:
+	  // We have to check for long double in order to support
+	  // i386 excess precision.
+	  if (mode == TYPE_MODE(complex_long_double_type_node))
+	    return complex_long_double_type_node;
+	}
+    }
+
+#if HOST_BITS_PER_WIDE_INT >= 64
+  /* The middle-end and some backends rely on TImode being supported
+     for 64-bit HWI.  */
+  if (mode == TImode)
+    {
+      type = build_nonstandard_integer_type (GET_MODE_BITSIZE (TImode),
+					     unsignedp);
+      if (type && TYPE_MODE (type) == TImode)
+	return type;
+    }
+#endif
+  return NULL_TREE;
+}
+
+/* Implementation of LANG_HOOKS_BUILTIN_FUNCTION.  */
+
+static tree
+rtl_langhook_builtin_function (tree decl)
+{
+  return decl;
+}
+
+/* Implementation of LANG_HOOKS_GLOBAL_BINDINGS_P.
+   Return true if we are in the global binding level.  */
+
+static bool
+rtl_langhook_global_bindings_p (void)
+{
+  return current_function_decl == NULL_TREE;
+}
+
+/* Implementation of LANG_HOOKS_PUSHDECL.  */
+
+static tree
+rtl_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+/* Implementation of LANG_HOOKS_GETDECLS.  */
+
+static tree
+rtl_langhook_getdecls (void)
+{
+  return NULL;
+}
+
+/* Functions called directly by the generic backend.  */
+
+/* Implementation of "convert" taken from the Go frontend.  */
+
+tree
+convert (tree type, tree expr)
+{
+  if (type == error_mark_node
+      || expr == error_mark_node
+      || TREE_TYPE (expr) == error_mark_node)
+    return error_mark_node;
+
+  if (type == TREE_TYPE (expr))
+    return expr;
+
+  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
+    return fold_convert (type, expr);
+
+  switch (TREE_CODE (type))
+    {
+    case VOID_TYPE:
+    case BOOLEAN_TYPE:
+      return fold_convert (type, expr);
+    case INTEGER_TYPE:
+      return fold (convert_to_integer (type, expr));
+    case POINTER_TYPE:
+      return fold (convert_to_pointer (type, expr));
+    case REAL_TYPE:
+      return fold (convert_to_real (type, expr));
+    case COMPLEX_TYPE:
+      return fold (convert_to_complex (type, expr));
+    default:
+      break;
+    }
+
+  gcc_unreachable ();
+}
+
+#undef LANG_HOOKS_NAME
+#undef LANG_HOOKS_INIT
+#undef LANG_HOOKS_OPTION_LANG_MASK
+#undef LANG_HOOKS_HANDLE_OPTION
+#undef LANG_HOOKS_PARSE_FILE
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#undef LANG_HOOKS_PUSHDECL
+#undef LANG_HOOKS_GETDECLS
+
+#define LANG_HOOKS_NAME			"GCC RTL frontend"
+#define LANG_HOOKS_INIT			rtl_langhook_init
+#define LANG_HOOKS_OPTION_LANG_MASK	rtl_langhook_option_lang_mask
+#define LANG_HOOKS_HANDLE_OPTION	rtl_langhook_handle_option
+#define LANG_HOOKS_PARSE_FILE		rtl_langhook_parse_file
+#define LANG_HOOKS_TYPE_FOR_MODE	rtl_langhook_type_for_mode
+#define LANG_HOOKS_TYPE_FOR_SIZE	rtl_langhook_type_for_size
+#define LANG_HOOKS_BUILTIN_FUNCTION	rtl_langhook_builtin_function
+#define LANG_HOOKS_GLOBAL_BINDINGS_P	rtl_langhook_global_bindings_p
+#define LANG_HOOKS_PUSHDECL		rtl_langhook_pushdecl
+#define LANG_HOOKS_GETDECLS		rtl_langhook_getdecls
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-rtl-rtl-frontend.h"
+#include "gtype-rtl.h"
diff --git a/gcc/run-one-rtl-pass.c b/gcc/run-one-rtl-pass.c
new file mode 100644
index 0000000..ced81a2
--- /dev/null
+++ b/gcc/run-one-rtl-pass.c
@@ -0,0 +1,119 @@
+/* run-one-rtl-pass.c - Run just one RTL pass
+   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 "target.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "stor-layout.h"
+#include "debug.h"
+#include "convert.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "common/common-target.h"
+#include "read-md.h"
+#include <mpfr.h>
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "pass_manager.h"
+#include "toplev.h"
+#include "bitmap.h"
+#include "df.h"
+#include "regs.h"
+#include "varasm.h"
+#include "insn-addr.h"
+
+/*  Locate and run PASS_NAME on cfun.  */
+
+void
+run_one_rtl_pass_by_name (const char *pass_name)
+{
+  opt_pass *pass = g->get_passes ()->get_pass_by_name (pass_name);
+  if (!pass)
+    {
+      error_at (UNKNOWN_LOCATION, "unrecognized pass: %qs", pass_name);
+      return;
+    }
+
+  /* Forcibly create the dataflow instance.  We'll need to do this on passes
+     that normally occur after pass_df_initialize/pass_df_initialize_no_opt.  */
+  /* FIXME: better conditional logic here.  */
+  if (0 == strcmp (pass_name, "rtl-cse1")
+      || 0 == strcmp (pass_name, "rtl-fwprop1")
+      || 0 == strcmp (pass_name, "rtl-combine")
+      || 0 == strcmp (pass_name, "rtl-ira")
+      || 0 == strcmp (pass_name, "rtl-reload")
+      || 0 == strcmp (pass_name, "rtl-pro_and_epilogue"))
+    {
+      opt_pass *df_pass = g->get_passes ()->get_pass_by_name ("rtl-dfinit");
+      gcc_assert (df_pass);
+      current_function_decl = cfun->decl;
+      df_pass->execute (cfun);
+
+      /* The dataflow instance should now exist.  */
+      gcc_assert (df);
+
+      df_analyze ();
+    }
+
+  /* Ensure reg_renumber is set up.  */
+  resize_reg_info ();
+
+  max_regno = max_reg_num ();
+
+  /* Pass "reload" sets the global "reload_completed", and many things
+     depend on this (e.g. instructions in .md files).  */
+  /* FIXME: better conditional logic here.  */
+  if (0 == strcmp (pass_name, "rtl-final"))
+    reload_completed = 1;
+
+  /* The INSN_ADDRESSES vec is normally set up by shorten_branches; we must
+     manually set it up for passes that run after this.  */
+  /* FIXME: better conditional logic here.  */
+  if (0 == strcmp (pass_name, "rtl-final"))
+    INSN_ADDRESSES_ALLOC (get_max_uid ());
+
+  /* Run the user-specified pass.  */
+  bitmap_obstack_initialize (NULL);
+  bitmap_obstack_initialize (&reg_obstack);
+  pass_init_dump_file (pass);
+  current_function_decl = cfun->decl;
+  pass->execute (cfun);
+  current_function_decl = NULL;
+  if (dump_file)
+    print_rtl_with_bb (dump_file, get_insns (), dump_flags);
+  pass_fini_dump_file (pass);
+  bitmap_obstack_release (&reg_obstack);
+}
diff --git a/gcc/run-one-rtl-pass.h b/gcc/run-one-rtl-pass.h
new file mode 100644
index 0000000..40d60ba
--- /dev/null
+++ b/gcc/run-one-rtl-pass.h
@@ -0,0 +1,25 @@
+/* run-one-rtl-pass.h - Run just one RTL pass
+   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/>.  */
+
+#ifndef GCC_RUN_ONE_RTL_PASS_H
+#define GCC_RUN_ONE_RTL_PASS_H
+
+extern void run_one_rtl_pass_by_name (const char *pass_name);
+
+#endif /* GCC_RUN_ONE_RTL_PASS_H */
diff --git a/gcc/testsuite/lib/rtl-dg.exp b/gcc/testsuite/lib/rtl-dg.exp
new file mode 100644
index 0000000..8aa5943
--- /dev/null
+++ b/gcc/testsuite/lib/rtl-dg.exp
@@ -0,0 +1,64 @@
+#   Copyright (C) 1997, 1999, 2000, 2003, 2007 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+# 
+# This program 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/>.
+
+# Define rtl callbacks for dg.exp.
+
+# Load support procs.
+load_lib gcc-defs.exp
+
+proc rtl_target_compile { source dest type options } {
+    set result [target_compile $source $dest $type $options]
+    return $result
+}
+
+load_lib gcc-dg.exp
+
+proc rtl-dg-test { prog do_what extra_tool_flags } {
+    verbose "rtl-dg-test (rtl-dg.exp):" 3
+    verbose "  prog: $prog" 3
+    verbose "  do_what: $do_what" 3
+    verbose "  extra_tool_flags: $extra_tool_flags" 3
+
+    return [gcc-dg-test-1 rtl_target_compile $prog $do_what $extra_tool_flags]
+}
+
+
+proc rtl-dg-prune { system text } {
+    return [gcc-dg-prune $system $text]
+}
+
+# Modified dg-runtest that runs tests in both C++98 and C++11 modes
+# unless they specifically specify one or the other.
+proc rtl-dg-runtest { testcases default-extra-flags } {
+    global runtests
+
+    foreach test $testcases {
+	# look if this is dg-do-run test, in which case
+	# we cycle through the option list, otherwise we don't
+	if [expr [search_for $test "dg-do run"]] {
+	    set option_list $TORTURE_OPTIONS
+	} else {
+	    set option_list [list { -O } ]
+	}
+
+	set nshort [file tail [file dirname $test]]/[file tail $test]
+
+	foreach flags $option_list {
+	    verbose "Testing $nshort, $flags" 1
+	    dg-test $test $flags ${default-extra-flags}
+	}
+    }
+}
diff --git a/gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl b/gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl
new file mode 100644
index 0000000..0eafab3
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/aarch64/asr_div1.rtl
@@ -0,0 +1,32 @@
+;; { dg-do compile { target aarch64-*-* } }
+;; { dg-options "-mtune=cortex-a53 -fsingle-pass=rtl-combine -fdump-rtl-combine" }
+
+;; Taken from
+;;    gcc/testsuite/gcc.dg/asr_div1.c -O2 -fdump-rtl-all -mtune=cortex-a53
+;; for aarch64, hand editing the prev/next insns to 0 as needed, and
+;; editing whitespace to avoid over-long lines.  */
+
+(function "f1"
+  (insn-chain
+
+(insn 8 0 9 2 (set (reg:DI 78)
+        (lshiftrt:DI (reg:DI 76)
+            (const_int 32 [0x20])))
+        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14
+        641 {*aarch64_lshr_sisd_or_int_di3}
+     (expr_list:REG_DEAD (reg:DI 76)
+        (nil)))
+(insn 9 8 0 2 (set (reg:SI 79)
+        (ashiftrt:SI (subreg:SI (reg:DI 78) 0)
+            (const_int 3 [0x3])))
+        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14
+        642 {*aarch64_ashr_sisd_or_int_si3}
+     (expr_list:REG_DEAD (reg:DI 78)
+        (nil)))
+
+  ) ;; insn-chain
+) ;; function
+
+;; Verify that insns 8 and 9 get combined into a shift of 35 (0x23)
+;; { dg-final { scan-rtl-dump "allowing combination of insns 8 and 9" "combine" } }
+;; { dg-final { scan-rtl-dump "modifying insn i3     9: r79:SI#0=r76:DI>>0x23" "combine" } }
diff --git a/gcc/testsuite/rtl.dg/aarch64/pr71779.rtl b/gcc/testsuite/rtl.dg/aarch64/pr71779.rtl
new file mode 100644
index 0000000..96f6e3d
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/aarch64/pr71779.rtl
@@ -0,0 +1,44 @@
+;; { dg-do compile { target aarch64-*-* } }
+;; { dg-options "-fsingle-pass=rtl-cse1 -fdump-rtl-cse1" }
+
+;; Dump taken from comment 2 of PR 71779, of
+;; "...the relevant memory access coming out of expand"
+;; with basic block IDs added, and prev/next insns set to
+;; 0 at ends, and 'p' added to pseudo regnos.
+
+(function "fragment"
+  (insn-chain
+
+;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
+(insn 1045 0 1046 2 (set (reg:SI 480)
+        (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
+                    [flags 0xc0]
+                    <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+     y.c:12702 -1
+     (nil))
+(insn 1046 1045 1047 2 (set (reg/f:SI 479)
+        (lo_sum:SI (reg:SI 480)
+            (symbol_ref:SI ("isl_obj_map_vtable")
+               [flags 0xc0]
+               <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+     y.c:12702 -1
+     (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
+                             [flags 0xc0]
+                             <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)
+        (nil)))
+(insn 1047 1046 1048 2 (set (reg:DI 481)
+        (subreg:DI (reg/f:SI 479) 0)) y.c:12702 -1
+     (nil))
+(insn 1048 1047 1049 2 (set (zero_extract:DI (reg/v:DI 191 [ obj1D.17368 ])
+            (const_int 32 [0x20])
+            (const_int 0 [0]))
+        (reg:DI 481)) y.c:12702 -1
+     (nil))
+;; Extra insn, to avoid all of the above from being deleted by DCE
+(insn 1049 1048 0 2 (set (mem:DI (reg:DI 191) [1 i+0 S4 A32])
+                         (const_int 1 [0x1])) -1 (nil))
+
+  ) ;; insn-chain
+) ;; function
+
+;; TODO: scan the dump
diff --git a/gcc/testsuite/rtl.dg/cfg-extra-bb.rtl b/gcc/testsuite/rtl.dg/cfg-extra-bb.rtl
new file mode 100644
index 0000000..7da8870
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/cfg-extra-bb.rtl
@@ -0,0 +1,12 @@
+(function "extra_bb"
+  (insn-chain) ;; empty
+  (cfg
+     (bb 0 ;; entry
+       (edge 0 2 (flags 0x1)) ;; { dg-error "bb index 2 not referenced by insns" }
+     ) ;; bb
+     (bb 2
+       (edge 2 1 (flags 0x1))
+     ) ;; bb
+     (bb 1) ;; exit
+  ) ;; cfg
+)
diff --git a/gcc/testsuite/rtl.dg/cfg-missing-bb.rtl b/gcc/testsuite/rtl.dg/cfg-missing-bb.rtl
new file mode 100644
index 0000000..cd82d04
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/cfg-missing-bb.rtl
@@ -0,0 +1,16 @@
+(function "missing_bb"
+  (insn-chain
+    (note 2 0 3 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+    (note 3 2 0 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
+  ) ;; empty
+  (cfg ;; { dg-error "bb index 3 used in .insn-chain. but not listed in .cfg." }
+       ;; { dg-error "1 missing bb.s." "" { target *-*-*} 6 }
+     (bb 0 ;; entry
+       (edge 0 2 (flags 0x1))
+     ) ;; bb
+     (bb 2
+       (edge 2 1 (flags 0x1))
+     ) ;; bb
+     (bb 1) ;; exit
+  ) ;; cfg
+)
diff --git a/gcc/testsuite/rtl.dg/good-include.rtl b/gcc/testsuite/rtl.dg/good-include.rtl
new file mode 100644
index 0000000..24be829
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/good-include.rtl
@@ -0,0 +1,6 @@
+/* Verify that we can include fragments from another dump.
+   We give the included file a .md suffix to avoid it being
+   run by rtl.exp.  */
+
+(include "good-includee.md")
+/* TODO: verify that we have the instruction from the above file.  */
diff --git a/gcc/testsuite/rtl.dg/good-includee.md b/gcc/testsuite/rtl.dg/good-includee.md
new file mode 100644
index 0000000..3314c40
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/good-includee.md
@@ -0,0 +1,5 @@
+(function "test"
+  (insn-chain
+    (note 1 0 0 (nil) NOTE_INSN_DELETED)
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/rtl.dg/missing-include.rtl b/gcc/testsuite/rtl.dg/missing-include.rtl
new file mode 100644
index 0000000..f99f3ef
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/missing-include.rtl
@@ -0,0 +1 @@
+(include "does-not-exist.rtl") /* { dg-error "include file .does-not-exist.rtl. not found" } */
diff --git a/gcc/testsuite/rtl.dg/more-than-one-cfg.rtl b/gcc/testsuite/rtl.dg/more-than-one-cfg.rtl
new file mode 100644
index 0000000..7153e0f
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/more-than-one-cfg.rtl
@@ -0,0 +1,7 @@
+(function "more_than_one_cfg"
+  (insn-chain) ;; insn-chain
+
+  (cfg)
+  (cfg) ;; { dg-error "more than one 'cfg' directive" }
+
+) ;; function
diff --git a/gcc/testsuite/rtl.dg/rtl.exp b/gcc/testsuite/rtl.dg/rtl.exp
new file mode 100644
index 0000000..71bebb9
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/rtl.exp
@@ -0,0 +1,41 @@
+#   Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+# 
+# This program 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/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib rtl-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_RTLFLAGS
+if ![info exists DEFAULT_RTLFLAGS] then {
+    set DEFAULT_RTLFLAGS ""
+    # -fdump-tree-rtl-raw
+}
+
+# Initialize `dg'.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir *.rtl]]
+
+verbose "rtl.exp tests: $tests" 1
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_RTLFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/rtl.dg/test.c b/gcc/testsuite/rtl.dg/test.c
new file mode 100644
index 0000000..ebb8aef
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/test.c
@@ -0,0 +1,31 @@
+int test_1 (int i, int j, int k)
+{
+  if (i < j)
+    return k + 4;
+  else
+    return -k;
+}
+
+/* Example showing:
+   - data structure
+   - loop
+   - call to "abort".  */
+
+struct foo
+{
+  int count;
+  float *data;
+};
+
+float test_2 (struct foo *lhs, struct foo *rhs)
+{
+  float result = 0.0f;
+
+  if (lhs->count != rhs->count)
+    __builtin_abort ();
+
+  for (int i = 0; i < lhs->count; i++)
+    result += lhs->data[i] * rhs->data[i];
+
+  return result;
+}
diff --git a/gcc/testsuite/rtl.dg/unknown-insn-uid.rtl b/gcc/testsuite/rtl.dg/unknown-insn-uid.rtl
new file mode 100644
index 0000000..8e63ace
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/unknown-insn-uid.rtl
@@ -0,0 +1,6 @@
+(function "test"
+  (insn-chain
+    (note 6 1 0 2 [bb 2] NOTE_INSN_BASIC_BLOCK) ;; { dg-error "insn with UID 1 not found for operand 0 ..PREV_INSN.. of insn 6" }
+    (note 7 0 3 2 [bb 2] NOTE_INSN_BASIC_BLOCK) ;; { dg-error "insn with UID 3 not found for operand 1 ..NEXT_INSN.. of insn 7" }
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/rtl.dg/unknown-rtx-code.rtl b/gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
new file mode 100644
index 0000000..9930677
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
@@ -0,0 +1,5 @@
+(function "test"
+  (insn-chain
+    (not-a-valid-kind-of-insn 1 0 0) ;; { dg-error "unknown rtx code" }
+  ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/rtl.dg/x86_64/dfinit.rtl b/gcc/testsuite/rtl.dg/x86_64/dfinit.rtl
new file mode 100644
index 0000000..54370a6
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/dfinit.rtl
@@ -0,0 +1,102 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-dfinit -fdump-rtl-dfinit" } */
+
+/* Lightly-modified dump of test.c.247r.split1 for x86_64, with
+   "function" directives added by hand.  */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(function "test_1"
+  (insn-chain
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 3 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 29 3 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 29 13 30 3 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 30 29 16)
+(code_label 16 30 17 4 2 (nil) [1 uses])
+(note 17 16 18 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 4 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 5 3 (nil) [1 uses])
+(note 21 20 22 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 5 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 5 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 5 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+) ;; insn-chain
+
+   (crtl
+     (return_rtx
+       (reg/i:SI 0 ax)
+     ) ;; return_rtx
+   ) ;; crtl
+
+) ;; function
+
+/* Verify that the dataflow information matches what cc1 would have
+   generated.  In particular, in earlier versions of the RTL
+   frontend, the exit block use of reg 0 (ax) wasn't picked up
+   on, due to not setting up crtl->return_rtx based on
+   DECL_RESULT (fndecl).  */
+/* { dg-final { scan-rtl-dump ";;  exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+/* { dg-final { scan-rtl-dump ";;  regs ever live.*0 .ax. 1 .dx. 4 .si. 5 .di. 17 .flags." "dfinit" } } */
diff --git a/gcc/testsuite/rtl.dg/x86_64/final.rtl b/gcc/testsuite/rtl.dg/x86_64/final.rtl
new file mode 100644
index 0000000..dbcdd0b
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/final.rtl
@@ -0,0 +1,58 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-final -fdump-rtl-final" } */
+
+/* Lightly-modified dump of test.c.289r.dwarf2 for x86_64 target.  */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(function "test_1"
+  (insn-chain
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 32 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(note 32 6 5 2 NOTE_INSN_PROLOGUE_END)
+(note 5 32 31 2 NOTE_INSN_FUNCTION_BEG)
+(insn:TI 31 5 27 2 (set (reg:SI 0 ax [93])
+        (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+            (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 27 31 28 2 (parallel [
+            (set (reg:SI 1 dx [92])
+                (neg:SI (reg/v:SI 1 dx [orig:90 k ] [90])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_UNUSED (reg:CC 17 flags)
+        (nil)))
+(insn 28 27 29 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg/v:SI 5 di [orig:88 i ] [88])
+            (reg/v:SI 4 si [orig:89 j ] [89]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_DEAD (reg/v:SI 5 di [orig:88 i ] [88])
+        (expr_list:REG_DEAD (reg/v:SI 4 si [orig:89 j ] [89])
+            (nil))))
+(insn:TI 29 28 23 2 (set (reg:SI 0 ax [orig:87 <retval> ] [87])
+        (if_then_else:SI (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (reg:SI 1 dx [92])
+            (reg:SI 0 ax [93]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_DEAD (reg:CCGC 17 flags)
+        (expr_list:REG_DEAD (reg:SI 1 dx [92])
+            (nil))))
+(insn 23 29 34 2 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(jump_insn:TI 34 23 33 2 (simple_return) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil)
+ -> simple_return)
+(barrier 33 34 30)
+(note 30 33 0 (nil) NOTE_INSN_DELETED)
+
+  ) ;; insn-chain
+) ;; function
+
+/* Verify that asm was emitted.  */
+/* { dg-final { scan-assembler "test_1:" } } */
+/* { dg-final { scan-assembler ".cfi_startproc" } } */
+/* { dg-final { scan-assembler ".cfi_endproc" } } */
+
+/* Verify that the "simple_return" was recognized.
+   FIXME: this assumes i386.md.  */
+/* { dg-final { scan-assembler "ret" } } */
diff --git a/gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl b/gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl
new file mode 100644
index 0000000..f7798aa
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/into-cfglayout.rtl
@@ -0,0 +1,91 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-into_cfglayout -fdump-rtl-into_cfglayout" } */
+
+(function "test"
+  (insn-chain
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 4 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 14 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 14 13 15 4 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 15 14 16)
+(code_label 16 15 17 5 2 (nil) [1 uses])
+(note 17 16 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 5 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 5 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 6 3 (nil) [1 uses])
+(note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 6 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 6 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+) ;; insn-chain
+) ;; function
+
+/* The conversion to cfglayout should eliminate unconditional jump
+   instructions...  */
+/* { dg-final { scan-rtl-dump "Removing jump 14." "into_cfglayout" } }  */
+/* { dg-final { scan-rtl-dump-not "jump_insn 14" "into_cfglayout" } }  */
+/* { dg-final { scan-rtl-dump-not "barrier 15" "into_cfglayout" } }  */
+
+/* ...but conditional jumps should be preserved.  */
+/* { dg-final { scan-rtl-dump "jump_insn 10" "into_cfglayout" } }  */
diff --git a/gcc/testsuite/rtl.dg/x86_64/ira.rtl b/gcc/testsuite/rtl.dg/x86_64/ira.rtl
new file mode 100644
index 0000000..707895d
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/ira.rtl
@@ -0,0 +1,91 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-ira -fdump-rtl-ira" } */
+
+/* Lightly-modified dump of test.c.251r.asmcons for x86_64.  */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(function "test"
+(insn-chain
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 3 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 29 3 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 29 13 30 3 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 30 29 16)
+(code_label 16 30 17 4 2 (nil) [1 uses])
+(note 17 16 18 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 4 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 5 3 (nil) [1 uses])
+(note 21 20 22 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 5 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 5 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 5 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+
+) ;; insn-chain
+) ;; function
+
+/* Verify that IRA was run.  */
+/* { dg-final { scan-rtl-dump "Building IRA IR" "ira" } } */
diff --git a/gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl b/gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl
new file mode 100644
index 0000000..bfbe302
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/pro_and_epilogue.rtl
@@ -0,0 +1,44 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-pro_and_epilogue -fdump-rtl-pro_and_epilogue" } */
+
+/* Lightly-modified dump of test.c.259r.split2 for x86_64.  */
+
+(function "test_1"
+(insn-chain
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 5 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(note 5 6 31 2 NOTE_INSN_FUNCTION_BEG)
+(insn 31 5 27 2 (set (reg:SI 0 ax [93])
+        (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+            (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 27 31 28 2 (parallel [
+            (set (reg:SI 1 dx [92])
+                (neg:SI (reg/v:SI 1 dx [orig:90 k ] [90])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 28 27 29 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg/v:SI 5 di [orig:88 i ] [88])
+            (reg/v:SI 4 si [orig:89 j ] [89]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 29 28 23 2 (set (reg:SI 0 ax [orig:87 <retval> ] [87])
+        (if_then_else:SI (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (reg:SI 1 dx [92])
+            (reg:SI 0 ax [93]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 23 29 30 2 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(note 30 23 0 (nil) NOTE_INSN_DELETED)
+
+) ;; insn-chain
+) ;; function
+
+/* Verify that the prologue and epilogue were added.  */
+/* { dg-final { scan-rtl-dump-times "NOTE_INSN_PROLOGUE_END" 1 "pro_and_epilogue" } }  */
+
+/* We expect a jump_insn to "simple_return".  */
+/* { dg-final { scan-rtl-dump-times "simple_return" 2 "pro_and_epilogue" } }  */
+
diff --git a/gcc/testsuite/rtl.dg/x86_64/vregs.rtl b/gcc/testsuite/rtl.dg/x86_64/vregs.rtl
new file mode 100644
index 0000000..95f5310
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/vregs.rtl
@@ -0,0 +1,88 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsingle-pass=rtl-vregs -fdump-rtl-vregs" } */
+
+(function "test"
+(insn-chain
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 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 ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 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])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 4 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 14 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 14 13 15 4 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 15 14 16)
+(code_label 16 15 17 5 2 (nil) [1 uses])
+(note 17 16 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 5 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 5 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 6 3 (nil) [1 uses])
+(note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 6 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 6 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+
+) ;; insn-chain
+) ;; function
+
+/* The 9 instances of "virtual-stack-vars" should now all be "frame".  */
+/* { dg-final { scan-rtl-dump-times "frame" 9 "vregs" } }  */
+/* { dg-final { scan-rtl-dump-not "virtual-stack-vars" "vregs" } }  */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 5f80763..2bb42a1 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -477,6 +477,13 @@ compile_file (void)
 
   if (flag_syntax_only || flag_wpa)
     return;
+
+  /* The RTL frontend is currently only capable of running one pass; this
+     is done from within the parse_file langhook.
+     Hence we must return early here.  Fixing this would require
+     being able to run passes from a certain point onwards.  */
+  if (in_rtl_frontend_p)
+    return;
  
   /* Reset maximum_field_alignment, it can be adjusted by #pragma pack
      and this shouldn't influence any types built by the middle-end
-- 
1.8.5.3

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

* Re: RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-07 13:58           ` Bernd Schmidt
@ 2016-10-07 18:08             ` David Malcolm
  2016-10-12 10:45             ` [PATCH] print_rtx_function: integrate dumping of the CFG into the insn chain David Malcolm
                               ` (2 subsequent siblings)
  3 siblings, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-07 18:08 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches

On Fri, 2016-10-07 at 15:58 +0200, Bernd Schmidt wrote:
> On 10/07/2016 03:26 PM, David Malcolm wrote:
> > 
> > We could simply print the INSN_UID for CODE_LABELs; something like
> > this
> > (see the "(code_label 16" below):
> 
> I think that should work.

OK: we'll keep the INSN_UID for CODE_LABELs when suppressing it for
others.

Should we drop the "[1 uses]" in the code_label? i.e. should it look
like this:

    (code_label 16 [1 uses])

or this:

    (code_label 16)

> > You appear to have trimmed the idea of enclosing the insns with
> > (basic-block) directives without commenting on it.  Did you like
> > this
> > idea?
> 
> Sorry - I appear to have completely missed it.
> 
> > It would make the above look like:
> > 
> >   (basic-block 2
> >     ;; insns snipped
> >     (jump_insn (set (pc)
> >             (if_then_else (ge (reg:CCGC 17 flags)
> >                     (const_int 0 [0]))
> >                 (label_ref 16)
> >                 (pc))) "test.c":3
> >    -> 16)
> >   ) ;; basic-block 2
> >   (basic-block 4
> >     (note [bb 4] NOTE_INSN_BASIC_BLOCK)
> >     ;; insns snipped
> >     (jump_insn (set (pc) (label_ref 20)) "test.c":4
> >      -> 20)
> >   ) ;; basic-block 4
> >   (barrier)
> >   (basic-block 5
> >     (code_label 16 [1 uses])
> >     (note [bb 5] NOTE_INSN_BASIC_BLOCK)
> >     ;; etc
> >   ) ;; basic-block 5
> > 
> > Note how the above format expresses clearly that:
> > * the (barrier) is part of the insn chain, but not in a basic
> > block, and
> > * some insns can happen in a basic block
> 
> That looks really nice IMO. Except maybe drop the "-> 16" bit for the
> jump_insn (that's the JUMP_LABEL, isn't it?)

It is the JUMP_LABEL.  This can be an INSN_UID, but it can also be
"return" or "simple_return"; presumably we do want to print JUMP_LABEL
somehow, though maybe it's always possible to reconstruct it:

  (jump_insn (simple_return) "test.c":15
   -> simple_return)

> > Taking this idea further: if we have (basic-block) directives
> > integrated into the insn-chain like this, we could express the CFG
> > by
> > adding (edge) directives. Here's a suggestion for doing it with
> > (edge-from) and (edge-to) directives, expressing the predecessor
> > and
> > successor edges in the CFG, along with :
> 
> That also looks reasonable. Probably a small but maybe not a huge 
> improvement over the other syntax. Having both from and to edges
> seems 
> redundant but might help readability. The reader should check 
> consistency in that case.

Would you prefer if it just showed out-edges?  If so, should the
directive be just "(edge" rather than "(edge-to"?

Did you like the stringified flags? e.g.

    (edge-to 4 (flags "FALLTHRU"))

presumably with | separators within the string e.g.:

    (edge-to 4 (flags "ABNORMAL | EH"))

> > Should we spell "0" and "1" as "entry" and "exit" when
> > parsing/dumping
> > basic block indices? e.g.:
> > 
> >   (basic-block 2
> >     (edge-from entry)
> 
> If that can be done it would be an improvement.

Yes, it ought to be simple to do.

> > > I think maybe you want a separate compact form of insns and notes
> > > (cinsn/cnote maybe), with a flag selecting which gets written out
> > > in
> > > the
> > > dumper. The reader could then read them in like any other rtx
> > > code,
> > > and
> > > there'd be a postprocessing stage to reconstruct the insn chain.
> > 
> > By this separate compact form, do you mean the form we've been
> > discussing above, with no INSN_UID/PREV/NEXT, etc?  Or something
> > else?
> 
> Yes, the form we're discussing, except instead of (insn ...) you'd
> have 
> (cinsn ...), which I assume would make it easier for the reader and
> less 
> ambiguous overall.

By "reader" do you mean humans or computers? (or both?)

> > As for "cinsn", "cnote", how about just "insn" and "note", and
> > having
> > the compactness be expressed at the top of the dump e.g. implicitly
> > by
> > the presence of a "(function" directive.  Could even have a format
> > version specifier in the function directive, to give us some future
> > -proofing e.g.
> >   (function (format 20161007)
> > or somesuch.
> 
> Having it implicit should also be ok - I have no strong preference 
> really. I'm not sure we want versioning - better to have an automatic
> conversion if we ever feel we need to change the format.

OK

> > Do you want to want to try hand-edited a test case, using some of
> > the
> > format ideas we've been discussing?  That might suggest further
> > improvements to the format.
> 
> We'll definitely want to have a look at one or two. Also, we ought to
> try to set up situations we haven't discussed: ADDR_VECs (in light of
> the basic block dumping) and ASMs maybe. I'm probably forgetting
> some.

Example of an ADDR_VEC:
There was one of these in patch 4 of v1 of the patch kit
  https://gcc.gnu.org/ml/gcc-patches/2016-05/msg00355.html
in "rtl.dg/roundtrip/test-switch-after-expand.rtl"; it looks like this:

(jump_table_data 18 17 19 (nil) (addr_vec:DI [
            (label_ref:DI 66)
            (label_ref:DI 20)
            (label_ref:DI 20)
            (label_ref:DI 20)
            (label_ref:DI 20)
            (label_ref:DI 20)
            (label_ref:DI 20)
            (label_ref:DI 20)
            (label_ref:DI 20)
            (label_ref:DI 20)
            (label_ref:DI 20)
            (label_ref:DI 35)
            (label_ref:DI 40)
            (label_ref:DI 46)
            (label_ref:DI 52)
            (label_ref:DI 52)
            (label_ref:DI 52)
            (label_ref:DI 52)
            (label_ref:DI 52)
            (label_ref:DI 52)
            (label_ref:DI 52)
            (label_ref:DI 52)
            (label_ref:DI 52)
            (label_ref:DI 52)
            (label_ref:DI 25)
            (label_ref:DI 30)
        ]))

If we trim the INSN_UIDs and (nil) basic block, it would look like:

(jump_table_data (addr_vec:DI [
            (label_ref:DI 66)
           
 (label_ref:DI 20)
            (label_ref:DI 20)
           
 (label_ref:DI 20)
            (label_ref:DI 20)
           
 (label_ref:DI 20)
            (label_ref:DI 20)
           
 (label_ref:DI 20)
            (label_ref:DI 20)
           
 (label_ref:DI 20)
            (label_ref:DI 20)
           
 (label_ref:DI 35)
            (label_ref:DI 40)
           
 (label_ref:DI 46)
            (label_ref:DI 52)
           
 (label_ref:DI 52)
            (label_ref:DI 52)
           
 (label_ref:DI 52)
            (label_ref:DI 52)
           
 (label_ref:DI 52)
            (label_ref:DI 52)
           
 (label_ref:DI 52)
            (label_ref:DI 52)
           
 (label_ref:DI 52)
            (label_ref:DI 25)
           
 (label_ref:DI 30)
        ]))

which looks reasonable.


Example of an inline asm (for x86_64):

Given e.g.:

uint64_t
get_timestamp (void)
{
  uint64_t msr;
     
  asm volatile ("rdtsc\n\t"    // Returns the time in EDX:EAX.
		"shl $32, %%rdx\n\t"  // Shift the upper bits left.
		"or %%rdx, %0"        // 'Or' in the lower bits.
		: "=a" (msr)
		:
		: "rdx");
  return msr;
}

the dump at "final" currently contains:

(insn 6 2 5 2 (parallel [
            (set (reg:DI 0 ax [orig:89 msr ] [89])
                (asm_operands/v:DI ("rdtsc
        shl $32, %%rdx
        or %%rdx, %0") ("=a") 0 []
                     []
                     [] test-asm.c:8))
            (clobber (reg:DI 1 dx))
            (clobber (reg:CCFP 18 fpsr))
            (clobber (reg:CC 17 flags))
        ]) test-asm.c:8 -1
     (nil))

Editing it by hand to the currently proposed format (omitting insn
UIDs, basic block#s, INSN_CODE and various "(nil)"s) gives:

(insn (parallel [
            (set (reg:DI ax [orig:89 msr ] [89])
                (asm_operands/v:DI ("rdtsc
        shl $32, %%rdx
        or %%rdx, %0") ("=a") 0 []
                     []
                     [] "test-asm.c":8))
            (clobber (reg:DI dx))
            (clobber (reg:CCFP fpsr))
            (clobber (reg:CC flags))
        ]) "test-asm.c":8)

I think we need to escape the asm string, giving something like:

(insn (parallel [
            (set (reg:DI ax [orig:89 msr ] [89])
      
          (asm_operands/v:DI ("rdtsc\n\tshl $32, %%rdx\n\n\tor %%rdx,
%0") ("=a") 0 []
                     []
                     [] "test
-asm.c":8))
            (clobber (reg:DI dx))
            (clobber
(reg:CCFP fpsr))
            (clobber (reg:CC flags))
        ]) "test
-asm.c":8)

We should probably edit the "orig" thing:
   [orig:89 msr ] [89]
to lose the regno, for consistency, giving something like:

(insn (parallel [
            (set (reg:DI ax [orig:msr])
               
 (asm_operands/v:DI ("rdtsc\n\tshl $32, %%rdx\n\n\tor %%rdx, %0")
("=a") 0 []
                     []
                     [] "test
-asm.c":8))
            (clobber (reg:DI dx))
            (clobber
(reg:CCFP fpsr))
            (clobber (reg:CC flags))
        ]) "test
-asm.c":8)

Does this look sane?

> One other thing in terms of format is the printout of CONST_INT - I 
> think it should suffice to have either decimal, or hex, but not
> really 
> both. The reader should maybe accept either.

OK, that will make things a little less verbose.

> I think all hosts have 64-bit HWI these days, so CONST_INT ought to 
> always stay valid through a roundtrip.
> 
> I may have missed it, but is there any kind of provision yet for 
> providing an "after" dump for what is expected after a pass is run? 
> Might be worth thinking about whether the reader could have a mode
> where 
> it matches internal RTL against an input.

Interesting idea.  Are you hoping for an exact match?  I'm a bit
nervous that this could over-specifier behavior, making test cases
brittle.

> > OK.  If so, do we need to print the regno for hard registers?  Or
> > should we just print the name for those, for consistency with
> > virtual
> > regs?  (i.e. have it be controlled by the same flag?)
> 
> Just the name should work, leaving only pseudos with numbers - that 
> ought to be reasonable. 

OK

> In the reader, when encountering a reg with a 
> number, just add FIRST_PSEUDO_REGISTER, and you should end up with 
> something that's consistent. Or maybe even dump the expected 
> FIRST_PSEUDO_REGISTER, and adjust for it in case the one we have at 
> run-time differs.

Another idea might be to give the pseudos names, so that all regs have
names: so that we'd have "pseudo-5", "pseudo-6", etc.

(given that 
#define FIRST_VIRTUAL_REGISTER	(FIRST_PSEUDO_REGISTER)
#define LAST_VIRTUAL_REGISTER		((FIRST_VIRTUAL_REGISTER)
+ 5)
)


> > > Does the C one have an advantage in terms of meaningful decls in
> > > MEM_ATTRs/SYMBOL_REFs?
> > 
> > Probably.
> 
> I think that might be the more promising path then.
> 
> 
> Bernd

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

* Re: [PATCH 10/16] Introduce class function_reader (v3)
  2016-10-07 13:44     ` David Malcolm
@ 2016-10-10 18:53       ` Richard Sandiford
  0 siblings, 0 replies; 96+ messages in thread
From: Richard Sandiford @ 2016-10-10 18:53 UTC (permalink / raw)
  To: David Malcolm; +Cc: Bernd Schmidt, gcc-patches

David Malcolm <dmalcolm@redhat.com> writes:
> On Wed, 2016-10-05 at 18:00 +0200, Bernd Schmidt wrote:
>> On 10/05/2016 06:15 PM, David Malcolm wrote:
>> > 	* errors.c: Use consistent pattern for bconfig.h vs config.h
>> > 	includes.
>> > 	(progname): Wrap with #ifdef GENERATOR_FILE.
>> > 	(error): Likewise.  Add "error: " to message.
>> > 	(fatal): Likewise.
>> > 	(internal_error): Likewise.
>> > 	(trim_filename): Likewise.
>> > 	(fancy_abort): Likewise.
>> > 	* errors.h (struct file_location): Move here from read-md.h.
>> > 	(file_location::file_location): Likewise.
>> > 	(error_at): New decl.
>> 
>> Can you split these out into a separate patch as well? I'll require
>> more 
>> explanation for them and they seem largely independent.
>
> [CCing Richard Sandiford]
>
> The gen* tools have their own diagnostics system, in errors.c:
>
> /* warning, error, and fatal.  These definitions are suitable for use
>    in the generator programs; the compiler has a more elaborate suite
>    of diagnostic printers, found in diagnostic.c.  */
>
> with file locations tracked using read-md.h's struct file_location,
> rather than location_t (aka libcpp's source_location).
>
> Implementing an RTL frontend by using the RTL reader from read-rtl.c
> means that we now need a diagnostics subsystem on the *host* for
> handling errors in RTL files, rather than just on the build machine.
>
> There seem to be two ways to do this:
>
>   (A) build the "light" diagnostics system (errors.c) for the host as
> well as build machine, and link it with the RTL reader there, so there
> are two parallel diagnostics subsystems.
>
>   (B) build the "real" diagnostics system (diagnostics*) for the
> *build* machine as well as the host, and use it from the gen* tools,
> eliminating the "light" system, and porting the gen* tools to use
> libcpp for location tracking.
>
> Approach (A) seems to be simpler, which is what this part of the patch
> does.
>
> I've experimented with approach (B).  I think it's doable, but it's
> much more invasive (perhaps needing a libdiagnostics.a and a
> build/libdiagnostics.a in gcc/Makefile.in), so I hope this can be
> followup work.
>
> I can split the relevant parts out into a separate patch, but I was
> wondering if either of you had a strong opinion on (A) vs (B) before I
> do so?

(A) sounds fine to me FWIW.  And sorry for the slow reply.

Thanks,
Richard

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

* Re: [PATCH 01/16] read-md.c: Add various cleanups to ~rtx_reader
  2016-10-05 15:51   ` Bernd Schmidt
@ 2016-10-11 15:15     ` David Malcolm
  2016-10-12 21:57       ` Richard Sandiford
  0 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-11 15:15 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: Richard Sandiford

On Wed, 2016-10-05 at 17:51 +0200, Bernd Schmidt wrote:
> On 10/05/2016 06:14 PM, David Malcolm wrote:
> > The selftests for the RTL frontend require supporting multiple
> > reader instances being alive one after another in-process, so
> > this lack of cleanup would become a leak.
> 
> > +  /* Initialize global data.  */
> > +  obstack_init (&string_obstack);
> > +  ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p,
> > 0);
> > +  obstack_init (&ptr_loc_obstack);
> > +  joined_conditions = htab_create (161, leading_ptr_hash,
> > leading_ptr_eq_p, 0);
> > +  obstack_init (&joined_conditions_obstack);
> > +  md_constants = htab_create (31, leading_string_hash,
> > +			      leading_string_eq_p, (htab_del) 0);
> > +  enum_types = htab_create (31, leading_string_hash,
> > +			    leading_string_eq_p, (htab_del) 0);
> > +
> > +  /* Unlock the stdio streams.  */
> > +  unlock_std_streams ();
> 
> Hmm, but these are global statics. Shouldn't they first be moved to 
> become class members?

[CCing Richard Sandiford]

I tried to move these into class rtx_reader, but doing so rapidly
became quite invasive, with many of functions in the gen* tools
becoming methods.

Arguably that would be a good thing, but there are a couple of issues:

(a) some of these functions take "vec" arguments; moving them from
static functions to being class methods requires that vec.h has been
included when the relevant class decl is parsed.

(b) rtx_reader turns into a bug dumping ground of methods, for the
union of all of the various gen* tools.

One way to alleviate these issues would be to do the split of
rtx_reader into base_rtx_reader vs rtx_reader from patch 9 of the kit:
  https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00273.html
and perhaps to split out part of read-md.h into a new read-rtl.h.

Before I reorganize the patches, does this approach sound reasonable?

Alternatively, a less invasive approach is to have an accessor for
these fields, so that things using them can get at them via the
rtx_reader_ptr singleton e.g.:

void
grow_string_obstack (char ch)
{
   obstack_1grow (rtx_reader_ptr->get_string_obstack (), ch);
}

and similar.

Thoughts?
Dave

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

* Re: [PATCH 09/16] Split class rtx_reader into base_rtx_reader vs rtx_reader
  2016-10-05 15:45 ` [PATCH 09/16] Split class rtx_reader into base_rtx_reader vs rtx_reader David Malcolm
@ 2016-10-11 15:53   ` Bernd Schmidt
  2016-10-18 20:30     ` David Malcolm
  0 siblings, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-11 15:53 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/05/2016 06:15 PM, David Malcolm wrote:
> -	  rtx_reader_ptr->get_top_level_filename ());
> +	  base_rtx_reader_ptr->get_top_level_filename ());

I wonder if the number of changes could be minimized by retaining the 
name rtx_reader for the base class, and using something more specific 
for the derived ones. Or would that require renaming a bunch of other 
locations?

> -static void
> -read_rtx_operand (rtx return_rtx, int idx)
> +rtx
> +rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
>  {
>    RTX_CODE code = GET_CODE (return_rtx);
>    const char *format_ptr = GET_RTX_FORMAT (code);

 > +
 > +  return return_rtx;
 >  }
 >

This appears to be an unrelated change. The return value needs to be 
documented.


Bernd

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

* [PATCH] print_rtx_function: integrate dumping of the CFG into the insn chain
  2016-10-07 13:58           ` Bernd Schmidt
  2016-10-07 18:08             ` David Malcolm
@ 2016-10-12 10:45             ` David Malcolm
  2016-10-12 10:50               ` Bernd Schmidt
  2016-10-12 17:17             ` [PATCH] Add a "compact" mode to print_rtx_function David Malcolm
  2016-10-19 14:36             ` RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader) David Malcolm
  3 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-12 10:45 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm

On Fri, 2016-10-07 at 15:58 +0200, Bernd Schmidt wrote:
> On 10/07/2016 03:26 PM, David Malcolm wrote:
> > 
> > We could simply print the INSN_UID for CODE_LABELs; something like
> > this
> > (see the "(code_label 16" below):
> 
> I think that should work.
> 
> > You appear to have trimmed the idea of enclosing the insns with
> > (basic-block) directives without commenting on it.  Did you like
> > this
> > idea?
> 
> Sorry - I appear to have completely missed it.
> 
> > It would make the above look like:
> > 
> >   (basic-block 2
> >     ;; insns snipped
> >     (jump_insn (set (pc)
> >             (if_then_else (ge (reg:CCGC 17 flags)
> >                     (const_int 0 [0]))
> >                 (label_ref 16)
> >                 (pc))) "test.c":3
> >    -> 16)
> >   ) ;; basic-block 2
> >   (basic-block 4
> >     (note [bb 4] NOTE_INSN_BASIC_BLOCK)
> >     ;; insns snipped
> >     (jump_insn (set (pc) (label_ref 20)) "test.c":4
> >      -> 20)
> >   ) ;; basic-block 4
> >   (barrier)
> >   (basic-block 5
> >     (code_label 16 [1 uses])
> >     (note [bb 5] NOTE_INSN_BASIC_BLOCK)
> >     ;; etc
> >   ) ;; basic-block 5
> > 
> > Note how the above format expresses clearly that:
> > * the (barrier) is part of the insn chain, but not in a basic
> > block, and
> > * some insns can happen in a basic block
> 
> That looks really nice IMO. Except maybe drop the "-> 16" bit for the
> jump_insn (that's the JUMP_LABEL, isn't it?)
> 
> > Taking this idea further: if we have (basic-block) directives
> > integrated into the insn-chain like this, we could express the CFG
> > by
> > adding (edge) directives. Here's a suggestion for doing it with
> > (edge-from) and (edge-to) directives, expressing the predecessor
> > and
> > successor edges in the CFG, along with :
> 
> That also looks reasonable. Probably a small but maybe not a huge
> improvement over the other syntax. Having both from and to edges
> seems
> redundant but might help readability. The reader should check
> consistency in that case.
> 
> > Should we spell "0" and "1" as "entry" and "exit" when
> > parsing/dumping
> > basic block indices? e.g.:
> > 
> >   (basic-block 2
> >     (edge-from entry)
> 
> If that can be done it would be an improvement.

The following patch implements the above idea, integrating (block)
directives into the (insn-chain) which wrap those rtx_insn * that
have a basic block.

It doesn't yet suppress printing the various INSN_UID fields, along
with the other ideas in this thread; I plan to do these as followups.

> > > I think maybe you want a separate compact form of insns and notes
> > > (cinsn/cnote maybe), with a flag selecting which gets written out
> > > in
> > > the
> > > dumper. The reader could then read them in like any other rtx
> > > code,
> > > and
> > > there'd be a postprocessing stage to reconstruct the insn chain.
> > 
> > By this separate compact form, do you mean the form we've been
> > discussing above, with no INSN_UID/PREV/NEXT, etc?  Or something
> > else?
> 
> Yes, the form we're discussing, except instead of (insn ...) you'd
> have
> (cinsn ...), which I assume would make it easier for the reader and
> less
> ambiguous overall.
> 
> > As for "cinsn", "cnote", how about just "insn" and "note", and
> > having
> > the compactness be expressed at the top of the dump e.g. implicitly
> > by
> > the presence of a "(function" directive.  Could even have a format
> > version specifier in the function directive, to give us some future
> > -proofing e.g.
> >   (function (format 20161007)
> > or somesuch.
> 
> Having it implicit should also be ok - I have no strong preference
> really. I'm not sure we want versioning - better to have an automatic
> conversion if we ever feel we need to change the format.
> 
> > Do you want to want to try hand-edited a test case, using some of
> > the
> > format ideas we've been discussing?  That might suggest further
> > improvements to the format.
> 
> We'll definitely want to have a look at one or two. Also, we ought to
> try to set up situations we haven't discussed: ADDR_VECs (in light of
> the basic block dumping) and ASMs maybe. I'm probably forgetting
> some.
> 
> One other thing in terms of format is the printout of CONST_INT - I
> think it should suffice to have either decimal, or hex, but not
> really
> both. The reader should maybe accept either.
> 
> I think all hosts have 64-bit HWI these days, so CONST_INT ought to
> always stay valid through a roundtrip.
> 
> I may have missed it, but is there any kind of provision yet for
> providing an "after" dump for what is expected after a pass is run?
> Might be worth thinking about whether the reader could have a mode
> where
> it matches internal RTL against an input.
> 
> > OK.  If so, do we need to print the regno for hard registers?  Or
> > should we just print the name for those, for consistency with
> > virtual
> > regs?  (i.e. have it be controlled by the same flag?)
> 
> Just the name should work, leaving only pseudos with numbers - that
> ought to be reasonable. In the reader, when encountering a reg with a
> number, just add FIRST_PSEUDO_REGISTER, and you should end up with
> something that's consistent. Or maybe even dump the expected
> FIRST_PSEUDO_REGISTER, and adjust for it in case the one we have at
> run-time differs.
> 
> > > Does the C one have an advantage in terms of meaningful decls in
> > > MEM_ATTRs/SYMBOL_REFs?
> > 
> > Probably.
> 
> I think that might be the more promising path then.
> 
> 
> Bernd

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu (on top
of this approved patch to add selftest::read_file:
  https://gcc.gnu.org/ml/gcc-patches/2016-09/msg00476.html
of which Jeff said "Seems reasonable.  Install when you have a need.":
  https://gcc.gnu.org/ml/gcc-patches/2016-09/msg01095.html
which this patch makes selftest::test_expansion_to_rtl make use of.

OK for trunk?

gcc/ChangeLog:
	* function-tests.c: Include "print-rtl.h".
	(selftest::test_expansion_to_rtl): Call print_rtx_function on the
	function, and verify what is dumped.
	* print-rtl-function.c (print_edge): New function.
	(begin_any_block): New function.
	(end_any_block): New function.
	(can_have_basic_block_p): New function.
	(print_rtx_function): Track the basic blocks of insns in the
	chain, wrapping those that are within blocks within "(block)"
	directives.  Remove the "(cfg)" directive.
---
 gcc/function-tests.c     |  23 +++++++
 gcc/print-rtl-function.c | 156 +++++++++++++++++++++++++++++++++++------------
 2 files changed, 140 insertions(+), 39 deletions(-)

diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index 4152cd3..04df8d8 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -78,6 +78,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-ref.h"
 #include "cgraph.h"
 #include "selftest.h"
+#include "print-rtl.h"
 
 #if CHECKING_P
 
@@ -643,6 +644,28 @@ test_expansion_to_rtl ()
 
   /* ...etc; any further checks are likely to over-specify things
      and run us into target dependencies.  */
+
+  /* Verify that print_rtl_function is sane.  */
+  named_temp_file tmp_out (".rtl");
+  FILE *outfile = fopen (tmp_out.get_filename (), "w");
+  print_rtx_function (outfile, fun);
+  fclose (outfile);
+
+  char *dump = read_file (SELFTEST_LOCATION,
+			  tmp_out.get_filename ());
+  ASSERT_STR_CONTAINS (dump, "(function \"test_fn\"\n");
+  ASSERT_STR_CONTAINS (dump, "  (insn-chain\n");
+  ASSERT_STR_CONTAINS (dump, "    (block 2\n");
+  ASSERT_STR_CONTAINS (dump, "      (edge-from entry (flags \"FALLTHRU\"))\n");
+  ASSERT_STR_CONTAINS (dump, "      (insn "); /* ...etc.  */
+  ASSERT_STR_CONTAINS (dump, "      (edge-to exit (flags \"FALLTHRU\"))\n");
+  ASSERT_STR_CONTAINS (dump, "    ) ;; block 2\n");
+  ASSERT_STR_CONTAINS (dump, "  ) ;; insn-chain\n");
+  ASSERT_STR_CONTAINS (dump, "  (crtl\n");
+  ASSERT_STR_CONTAINS (dump, "  ) ;; crtl\n");
+  ASSERT_STR_CONTAINS (dump, ") ;; function \"test_fn\"\n");
+
+  free (dump);
 }
 
 /* Run all of the selftests within this file.  */
diff --git a/gcc/print-rtl-function.c b/gcc/print-rtl-function.c
index c4b99c0..ba883fa 100644
--- a/gcc/print-rtl-function.c
+++ b/gcc/print-rtl-function.c
@@ -33,14 +33,102 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "emit-rtl.h"
 
+/* Print an "(edge-from)" or "(edge-to)" directive describing E
+   to OUTFILE.  */
+
+static void
+print_edge (FILE *outfile, edge e, bool from)
+{
+  fprintf (outfile, "      (%s ", from ? "edge-from" : "edge-to");
+  basic_block bb = from ? e->src : e->dest;
+  gcc_assert (bb);
+  switch (bb->index)
+    {
+    case ENTRY_BLOCK:
+      fprintf (outfile, "entry");
+      break;
+    case EXIT_BLOCK:
+      fprintf (outfile, "exit");
+      break;
+    default:
+      fprintf (outfile, "%i", bb->index);
+      break;
+    }
+
+  /* Express edge flags as a string with " | " separator.
+     e.g. (flags "FALLTHRU | DFS_BACK").  */
+  fprintf (outfile, " (flags \"");
+  bool seen_flag = false;
+#define DEF_EDGE_FLAG(NAME,IDX) \
+  do {						\
+    if (e->flags & EDGE_##NAME)			\
+      {						\
+	if (seen_flag)				\
+	  fprintf (outfile, " | ");		\
+	fprintf (outfile, "%s", (#NAME));	\
+	seen_flag = true;			\
+      }						\
+  } while (0);
+#include "cfg-flags.def"
+#undef DEF_EDGE_FLAG
+
+  fprintf (outfile, "\"))\n");
+}
+
+/* If BB is non-NULL, print the start of a "(block)" directive for it
+   to OUTFILE, otherwise do nothing.  */
+
+static void
+begin_any_block (FILE *outfile, basic_block bb)
+{
+  if (!bb)
+    return;
+
+  edge e;
+  edge_iterator ei;
+
+  fprintf (outfile, "    (block %i\n", bb->index);
+  FOR_EACH_EDGE (e, ei, bb->preds)
+    print_edge (outfile, e, true);
+}
+
+/* If BB is non-NULL, print the end of a "(block)" directive for it
+   to OUTFILE, otherwise do nothing.  */
+
+static void
+end_any_block (FILE *outfile, basic_block bb)
+{
+  if (!bb)
+    return;
+
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    print_edge (outfile, e, false);
+  fprintf (outfile, "    ) ;; block %i\n", bb->index);
+}
+
+/* Determine if INSN is of a kind that can have a basic block.  */
+
+static bool
+can_have_basic_block_p (const rtx_insn *insn)
+{
+  return GET_RTX_FORMAT (GET_CODE (insn))[2] == 'B';
+}
+
 /* Write FN to OUTFILE in a form suitable for parsing, with indentation
-   and comments to make the structure easy for a human to grok.
+   and comments to make the structure easy for a human to grok.  Track
+   the basic blocks of insns in the chain, wrapping those that are within
+   blocks within "(block)" directives.
 
    Example output:
 
-     (function "times_two"
-       (insn-chain
-	 (note 1 0 4 (nil) NOTE_INSN_DELETED)
+   (function "times_two"
+     (insn-chain
+       (note 1 0 4 (nil) NOTE_INSN_DELETED)
+       (block 2
+	 (edge-from entry (flags "FALLTHRU"))
 	 (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])
@@ -69,23 +157,15 @@ along with GCC; see the file COPYING3.  If not see
 		  (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"
+	 (edge-to exit (flags "FALLTHRU"))
+       ) ;; block 2
+     ) ;; insn-chain
+     (crtl
+       (return_rtx
+	  (reg/i:SI 0 ax)
+       ) ;; return_rtx
+     ) ;; crtl
+   ) ;; function "times_two"
 */
 
 DEBUG_FUNCTION void
@@ -99,27 +179,25 @@ print_rtx_function (FILE *outfile, function *fn)
 
   /* The instruction chain.  */
   fprintf (outfile, "  (insn-chain\n");
+  basic_block curr_bb = NULL;
   for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    print_rtl_single_with_indent (outfile, insn, 4);
+    {
+      basic_block insn_bb;
+      if (can_have_basic_block_p (insn))
+	insn_bb = BLOCK_FOR_INSN (insn);
+      else
+	insn_bb = NULL;
+      if (curr_bb != insn_bb)
+	{
+	  end_any_block (outfile, curr_bb);
+	  curr_bb = insn_bb;
+	  begin_any_block (outfile, curr_bb);
+	}
+      print_rtl_single_with_indent (outfile, insn, curr_bb ? 6 : 4);
+    }
+  end_any_block (outfile, curr_bb);
   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");
-- 
1.8.5.3

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

* Re: [PATCH] print_rtx_function: integrate dumping of the CFG into the insn chain
  2016-10-12 10:45             ` [PATCH] print_rtx_function: integrate dumping of the CFG into the insn chain David Malcolm
@ 2016-10-12 10:50               ` Bernd Schmidt
  0 siblings, 0 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-12 10:50 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/12/2016 01:15 PM, David Malcolm wrote:
> +/* Determine if INSN is of a kind that can have a basic block.  */
> +
> +static bool
> +can_have_basic_block_p (const rtx_insn *insn)
> +{
> +  return GET_RTX_FORMAT (GET_CODE (insn))[2] == 'B';
> +}

Oof. I suppose they're all at least that long, but still - we're looking 
only for barriers, right? Might be better to encode this expectation 
using an assert, like so:

rtx_code code = GET_CODE (insn);
if (code == BARRIER)
   return false;
gcc_assert (GET_RTX_FORMAT (code)[2] == 'B');

Otherwise, nice, and ok.


Bernd

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

* [PATCH] Add a "compact" mode to print_rtx_function
  2016-10-07 13:58           ` Bernd Schmidt
  2016-10-07 18:08             ` David Malcolm
  2016-10-12 10:45             ` [PATCH] print_rtx_function: integrate dumping of the CFG into the insn chain David Malcolm
@ 2016-10-12 17:17             ` David Malcolm
  2016-10-12 17:31               ` Bernd Schmidt
  2016-10-19 14:36             ` RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader) David Malcolm
  3 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-12 17:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, David Malcolm

On Fri, 2016-10-07 at 15:58 +0200, Bernd Schmidt wrote:
> On 10/07/2016 03:26 PM, David Malcolm wrote:
> > 
> > We could simply print the INSN_UID for CODE_LABELs; something like
> > this
> > (see the "(code_label 16" below):
> 
> I think that should work.
> 
> > You appear to have trimmed the idea of enclosing the insns with
> > (basic-block) directives without commenting on it.  Did you like
> > this
> > idea?
> 
> Sorry - I appear to have completely missed it.
> 
> > It would make the above look like:
> > 
> >   (basic-block 2
> >     ;; insns snipped
> >     (jump_insn (set (pc)
> >             (if_then_else (ge (reg:CCGC 17 flags)
> >                     (const_int 0 [0]))
> >                 (label_ref 16)
> >                 (pc))) "test.c":3
> >    -> 16)
> >   ) ;; basic-block 2
> >   (basic-block 4
> >     (note [bb 4] NOTE_INSN_BASIC_BLOCK)
> >     ;; insns snipped
> >     (jump_insn (set (pc) (label_ref 20)) "test.c":4
> >      -> 20)
> >   ) ;; basic-block 4
> >   (barrier)
> >   (basic-block 5
> >     (code_label 16 [1 uses])
> >     (note [bb 5] NOTE_INSN_BASIC_BLOCK)
> >     ;; etc
> >   ) ;; basic-block 5
> > 
> > Note how the above format expresses clearly that:
> > * the (barrier) is part of the insn chain, but not in a basic
> > block, and
> > * some insns can happen in a basic block
> 
> That looks really nice IMO. Except maybe drop the "-> 16" bit for the
> jump_insn (that's the JUMP_LABEL, isn't it?)
> 
> > Taking this idea further: if we have (basic-block) directives
> > integrated into the insn-chain like this, we could express the CFG
> > by
> > adding (edge) directives. Here's a suggestion for doing it with
> > (edge-from) and (edge-to) directives, expressing the predecessor
> > and
> > successor edges in the CFG, along with :
> 
> That also looks reasonable. Probably a small but maybe not a huge
> improvement over the other syntax. Having both from and to edges
> seems
> redundant but might help readability. The reader should check
> consistency in that case.
> 
> > Should we spell "0" and "1" as "entry" and "exit" when
> > parsing/dumping
> > basic block indices? e.g.:
> > 
> >   (basic-block 2
> >     (edge-from entry)
> 
> If that can be done it would be an improvement.
> 
> > > I think maybe you want a separate compact form of insns and notes
> > > (cinsn/cnote maybe), with a flag selecting which gets written out
> > > in
> > > the
> > > dumper. The reader could then read them in like any other rtx
> > > code,
> > > and
> > > there'd be a postprocessing stage to reconstruct the insn chain.
> > 
> > By this separate compact form, do you mean the form we've been
> > discussing above, with no INSN_UID/PREV/NEXT, etc?  Or something
> > else?
> 
> Yes, the form we're discussing, except instead of (insn ...) you'd
> have
> (cinsn ...), which I assume would make it easier for the reader and
> less
> ambiguous overall.
> 
> > As for "cinsn", "cnote", how about just "insn" and "note", and
> > having
> > the compactness be expressed at the top of the dump e.g. implicitly
> > by
> > the presence of a "(function" directive.  Could even have a format
> > version specifier in the function directive, to give us some future
> > -proofing e.g.
> >   (function (format 20161007)
> > or somesuch.
> 
> Having it implicit should also be ok - I have no strong preference
> really. I'm not sure we want versioning - better to have an automatic
> conversion if we ever feel we need to change the format.
> 
> > Do you want to want to try hand-edited a test case, using some of
> > the
> > format ideas we've been discussing?  That might suggest further
> > improvements to the format.
> 
> We'll definitely want to have a look at one or two. Also, we ought to
> try to set up situations we haven't discussed: ADDR_VECs (in light of
> the basic block dumping) and ASMs maybe. I'm probably forgetting
> some.
> 
> One other thing in terms of format is the printout of CONST_INT - I
> think it should suffice to have either decimal, or hex, but not
> really
> both. The reader should maybe accept either.
> 
> I think all hosts have 64-bit HWI these days, so CONST_INT ought to
> always stay valid through a roundtrip.
> 
> I may have missed it, but is there any kind of provision yet for
> providing an "after" dump for what is expected after a pass is run?
> Might be worth thinking about whether the reader could have a mode
> where
> it matches internal RTL against an input.
> 
> > OK.  If so, do we need to print the regno for hard registers?  Or
> > should we just print the name for those, for consistency with
> > virtual
> > regs?  (i.e. have it be controlled by the same flag?)
> 
> Just the name should work, leaving only pseudos with numbers - that
> ought to be reasonable. In the reader, when encountering a reg with a
> number, just add FIRST_PSEUDO_REGISTER, and you should end up with
> something that's consistent. Or maybe even dump the expected
> FIRST_PSEUDO_REGISTER, and adjust for it in case the one we have at
> run-time differs.
> 
> > > Does the C one have an advantage in terms of meaningful decls in
> > > MEM_ATTRs/SYMBOL_REFs?
> > 
> > Probably.
> 
> I think that might be the more promising path then.

This patch implements a "compact" mode for print_rtx_function,
implementing most of the ideas above.

Example of output can be seen here:
  https://dmalcolm.fedorapeople.org/gcc/2016-10-12/test-switch-compact.rtl
which can be contrasted with the non-compact output here:
  https://dmalcolm.fedorapeople.org/gcc/2016-10-12/test-switch-noncompact.rtl

It adds the "c" prefix to the insn names, so we get "cinsn", etc.  However,
it does lead to things like this:

   (ccode_label 56 8 "")

which gives me pause: would the "ccode" in "ccode_label" be confusing? (compared
to "ccmode").  An alternative might be to have a "compact-insn-chain" vs
"insn-chain" wrapper element, expressing that this is a compact dump.

Successfully bootstrapped on x86_64-pc-linux-gnu; regrtesting in progress.

OK for trunk if it passes?

I think the only remaining item from our discussion above is what to do
about the numbering of pseudos in the dumps (currently it just prints the regno
unmodified).

Other than that, is the resultant dump format good enough that I can start
rewriting the RTL frontend parser, or are there other changes you'd want?

gcc/ChangeLog:
	* function-tests.c (selftest::test_expansion_to_rtl): Add "true"
	for new "compact" param of print_rtx_function.  Check for "cinsn"
	rather than "insn".
	* print-rtl-function.c (flag_compact): New decl.
	(print_rtx_function): Add param "compact" and use it to set
	flag_compact, adding a description of the effect to the leading
	comment, and updating the example output.
	* print-rtl.c (flag_compact): New variable.
	(print_rtx_operand_code_0): Omit the JUMP_LABEL reference in compact
	mode.
	(print_rtx_operand_code_i): When printing source locations, wrap
	xloc.file in quotes.  Don't print INSN_CODEs in compact mode.
	(print_rtx_operand_code_r): Don't print regnos for hard regs and
	virtuals in compact mode.
	(print_rtx_operand_code_u): Don't print insn UIDs in compact mode,
	apart from in LABEL_REFs.
	(print_rtx_operand): In case 'w', don't print in hex in compact mode.
	Don't print basic block ids in compact mode.
	(print_rtx):  In compact mode, prefix the code of insns with "c",
	only print the INSN_UID of CODE_LABELs, and omit their LABEL_NUSES.
	* print-rtl.h (print_rtx_function): Add "compact" param.
---
 gcc/function-tests.c     |  4 +--
 gcc/print-rtl-function.c | 76 +++++++++++++++++++++++++++--------------------
 gcc/print-rtl.c          | 77 ++++++++++++++++++++++++++++++++++--------------
 gcc/print-rtl.h          |  2 +-
 4 files changed, 102 insertions(+), 57 deletions(-)

diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index 049a07f9..b0c44cf 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -648,7 +648,7 @@ test_expansion_to_rtl ()
   /* Verify that print_rtl_function is sane.  */
   named_temp_file tmp_out (".rtl");
   FILE *outfile = fopen (tmp_out.get_filename (), "w");
-  print_rtx_function (outfile, fun);
+  print_rtx_function (outfile, fun, true);
   fclose (outfile);
 
   char *dump = read_file (SELFTEST_LOCATION, tmp_out.get_filename ());
@@ -656,7 +656,7 @@ test_expansion_to_rtl ()
   ASSERT_STR_CONTAINS (dump, "  (insn-chain\n");
   ASSERT_STR_CONTAINS (dump, "    (block 2\n");
   ASSERT_STR_CONTAINS (dump, "      (edge-from entry (flags \"FALLTHRU\"))\n");
-  ASSERT_STR_CONTAINS (dump, "      (insn "); /* ...etc.  */
+  ASSERT_STR_CONTAINS (dump, "      (cinsn "); /* ...etc.  */
   ASSERT_STR_CONTAINS (dump, "      (edge-to exit (flags \"FALLTHRU\"))\n");
   ASSERT_STR_CONTAINS (dump, "    ) ;; block 2\n");
   ASSERT_STR_CONTAINS (dump, "  ) ;; insn-chain\n");
diff --git a/gcc/print-rtl-function.c b/gcc/print-rtl-function.c
index 4f9b4ef..90a0ff7 100644
--- a/gcc/print-rtl-function.c
+++ b/gcc/print-rtl-function.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "emit-rtl.h"
 
+extern bool flag_compact;
+
 /* Print an "(edge-from)" or "(edge-to)" directive describing E
    to OUTFILE.  */
 
@@ -126,55 +128,63 @@ can_have_basic_block_p (const rtx_insn *insn)
    the basic blocks of insns in the chain, wrapping those that are within
    blocks within "(block)" directives.
 
-   Example output:
+   If COMPACT, then instructions are printed in a compact form:
+   - INSN_UIDs are omitted, except for jumps and CODE_LABELs,
+   - INSN_CODEs are omitted,
+   - register numbers are omitted for hard and virtual regs
+   - insn names are prefixed with "c" (e.g. "cinsn", "cnote", etc)
+
+   Example output (with COMPACT==true):
 
    (function "times_two"
      (insn-chain
-       (note 1 0 4 (nil) NOTE_INSN_DELETED)
+       (cnote NOTE_INSN_DELETED)
        (block 2
 	 (edge-from entry (flags "FALLTHRU"))
-	 (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))
+	 (cnote [bb 2] NOTE_INSN_BASIC_BLOCK)
+	 (cinsn (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+			       (const_int -4)) [1 i+0 S4 A32])
+		       (reg:SI di [ i ])) "t.c":2
+		   (nil))
+	 (cnote NOTE_INSN_FUNCTION_BEG)
+	 (cinsn (set (reg:SI 89)
+		       (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+			       (const_int -4)) [1 i+0 S4 A32])) "t.c":3
+		   (nil))
+	 (cinsn (parallel [
+			   (set (reg:SI 87 [ _2 ])
+			       (ashift:SI (reg:SI 89)
+				   (const_int 1)))
+			   (clobber (reg:CC flags))
+		       ]) "t.c":3
+		   (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+				   (const_int -4)) [1 i+0 S4 A32])
+			   (const_int 1))
+		       (nil)))
+	 (cinsn (set (reg:SI 88 [ <retval> ])
+		       (reg:SI 87 [ _2 ])) "t.c":3
+		   (nil))
+	 (cinsn (set (reg/i:SI ax)
+		       (reg:SI 88 [ <retval> ])) "t.c":4
+		   (nil))
+	 (cinsn (use (reg/i:SI ax)) "t.c":4
+		   (nil))
 	 (edge-to exit (flags "FALLTHRU"))
        ) ;; block 2
      ) ;; insn-chain
      (crtl
        (return_rtx
-	  (reg/i:SI 0 ax)
+	 (reg/i:SI ax)
        ) ;; return_rtx
      ) ;; crtl
    ) ;; function "times_two"
 */
 
 DEBUG_FUNCTION void
-print_rtx_function (FILE *outfile, function *fn)
+print_rtx_function (FILE *outfile, function *fn, bool compact)
 {
+  flag_compact = compact;
+
   tree fdecl = fn->decl;
 
   const char *dname = lang_hooks.decl_printable_name (fdecl, 2);
@@ -210,4 +220,6 @@ print_rtx_function (FILE *outfile, function *fn)
   fprintf (outfile, "  ) ;; crtl\n");
 
   fprintf (outfile, ") ;; function \"%s\"\n", dname);
+
+  flag_compact = false;
 }
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 29e8ee2..88e9f49 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -60,6 +60,13 @@ static int indent;
 
 static bool in_call_function_usage;
 
+/* If true, use compact dump format:
+   - INSN_UIDs are omitted, except for jumps and CODE_LABELs,
+   - INSN_CODEs are omitted,
+   - register numbers are omitted for hard and virtual regs
+   - insn names are prefixed with "c" (e.g. "cinsn", "cnote", etc).  */
+bool flag_compact;
+
 static void print_rtx (const_rtx);
 
 /* String printed at beginning of each RTL when it is dumped.
@@ -176,7 +183,8 @@ print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  break;
 	}
     }
-  else if (idx == 7 && JUMP_P (in_rtx) && JUMP_LABEL (in_rtx) != NULL)
+  else if (idx == 7 && JUMP_P (in_rtx) && JUMP_LABEL (in_rtx) != NULL
+	   && !flag_compact)
     {
       /* Output the JUMP_LABEL reference.  */
       fprintf (outfile, "\n%s%*s -> ", print_rtx_head, indent * 2, "");
@@ -284,7 +292,7 @@ print_rtx_operand_code_i (const_rtx in_rtx, int idx)
       if (INSN_HAS_LOCATION (in_insn))
 	{
 	  expanded_location xloc = insn_location (in_insn);
-	  fprintf (outfile, " %s:%i", xloc.file, xloc.line);
+	  fprintf (outfile, " \"%s\":%i", xloc.file, xloc.line);
 	}
 #endif
     }
@@ -335,6 +343,13 @@ print_rtx_operand_code_i (const_rtx in_rtx, int idx)
       const char *name;
       int is_insn = INSN_P (in_rtx);
 
+      /* Don't print INSN_CODEs in compact mode.  */
+      if (flag_compact && is_insn && &INSN_CODE (in_rtx) == &XINT (in_rtx, idx))
+	{
+	  sawclose = 0;
+	  return;
+	}
+
       if (flag_dump_unnumbered
 	  && (is_insn || NOTE_P (in_rtx)))
 	fputc ('#', outfile);
@@ -358,26 +373,28 @@ print_rtx_operand_code_r (const_rtx in_rtx)
   unsigned int regno = REGNO (in_rtx);
 
 #ifndef GENERATOR_FILE
+  /* For hard registers and virtuals, always print the
+     regno, except in compact mode.  */
+  if (regno <= LAST_VIRTUAL_REGISTER && !flag_compact)
+    fprintf (outfile, " %d", regno);
   if (regno < FIRST_PSEUDO_REGISTER)
-    fprintf (outfile, " %d %s", regno, reg_names[regno]);
+    fprintf (outfile, " %s", reg_names[regno]);
   else if (regno <= LAST_VIRTUAL_REGISTER)
     {
       if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
-	fprintf (outfile, " %d virtual-incoming-args", regno);
+	fprintf (outfile, " virtual-incoming-args");
       else if (regno == VIRTUAL_STACK_VARS_REGNUM)
-	fprintf (outfile, " %d virtual-stack-vars", regno);
+	fprintf (outfile, " virtual-stack-vars");
       else if (regno == VIRTUAL_STACK_DYNAMIC_REGNUM)
-	fprintf (outfile, " %d virtual-stack-dynamic", regno);
+	fprintf (outfile, " virtual-stack-dynamic");
       else if (regno == VIRTUAL_OUTGOING_ARGS_REGNUM)
-	fprintf (outfile, " %d virtual-outgoing-args", regno);
+	fprintf (outfile, " virtual-outgoing-args");
       else if (regno == VIRTUAL_CFA_REGNUM)
-	fprintf (outfile, " %d virtual-cfa", regno);
+	fprintf (outfile, " virtual-cfa");
       else if (regno == VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM)
-	fprintf (outfile, " %d virtual-preferred-stack-boundary",
-		 regno);
+	fprintf (outfile, " virtual-preferred-stack-boundary");
       else
-	fprintf (outfile, " %d virtual-reg-%d", regno,
-		 regno-FIRST_VIRTUAL_REGISTER);
+	fprintf (outfile, " virtual-reg-%d", regno-FIRST_VIRTUAL_REGISTER);
     }
   else
 #endif
@@ -410,6 +427,10 @@ print_rtx_operand_code_r (const_rtx in_rtx)
 static void
 print_rtx_operand_code_u (const_rtx in_rtx, int idx)
 {
+  /* Don't print insn UIDs in compact mode, apart from in LABEL_REFs.  */
+  if (flag_compact && GET_CODE (in_rtx) != LABEL_REF)
+    return;
+
   if (XEXP (in_rtx, idx) != NULL)
     {
       rtx sub = XEXP (in_rtx, idx);
@@ -492,7 +513,7 @@ print_rtx_operand (const_rtx in_rtx, int idx)
       if (! flag_simple)
 	fprintf (outfile, " ");
       fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, XWINT (in_rtx, idx));
-      if (! flag_simple)
+      if (! flag_simple && !flag_compact)
 	fprintf (outfile, " [" HOST_WIDE_INT_PRINT_HEX "]",
 		 (unsigned HOST_WIDE_INT) XWINT (in_rtx, idx));
       break;
@@ -533,6 +554,9 @@ print_rtx_operand (const_rtx in_rtx, int idx)
       break;
 
     case 'B':
+      /* Don't print basic block ids in compact mode.  */
+      if (flag_compact)
+	break;
 #ifndef GENERATOR_FILE
       if (XBBDEF (in_rtx, idx))
 	fprintf (outfile, " %i", XBBDEF (in_rtx, idx)->index);
@@ -575,7 +599,12 @@ print_rtx (const_rtx in_rtx)
     }
 
   /* Print name of expression code.  */
-  if (flag_simple && CONST_INT_P (in_rtx))
+
+  /* In compact mode, prefix the code of insns with "c",
+     giving "cinsn", "cnote" etc.  */
+  if (flag_compact && is_a <const rtx_insn *, const struct rtx_def> (in_rtx))
+    fprintf (outfile, "(c%s", GET_RTX_NAME (GET_CODE (in_rtx)));
+  else if (flag_simple && CONST_INT_P (in_rtx))
     fputc ('(', outfile);
   else
     fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx)));
@@ -639,13 +668,16 @@ print_rtx (const_rtx in_rtx)
     idx = 5;
 #endif
 
-  if (INSN_CHAIN_CODE_P (GET_CODE (in_rtx)))
-    {
-      if (flag_dump_unnumbered)
-	fprintf (outfile, " #");
-      else
-	fprintf (outfile, " %d", INSN_UID (in_rtx));
-    }
+  /* For insns, print the INSN_UID.
+     In compact mode, we only print the INSN_UID of CODE_LABELs.  */
+  if (!flag_compact || GET_CODE (in_rtx) == CODE_LABEL)
+    if (INSN_CHAIN_CODE_P (GET_CODE (in_rtx)))
+      {
+	if (flag_dump_unnumbered)
+	  fprintf (outfile, " #");
+	else
+	  fprintf (outfile, " %d", INSN_UID (in_rtx));
+      }
 
   /* Get the format string and skip the first elements if we have handled
      them already.  */
@@ -704,7 +736,8 @@ print_rtx (const_rtx in_rtx)
 #endif
 
     case CODE_LABEL:
-      fprintf (outfile, " [%d uses]", LABEL_NUSES (in_rtx));
+      if (!flag_compact)
+	fprintf (outfile, " [%d uses]", LABEL_NUSES (in_rtx));
       switch (LABEL_KIND (in_rtx))
 	{
 	  case LABEL_NORMAL: break;
diff --git a/gcc/print-rtl.h b/gcc/print-rtl.h
index 9cad683..7a1dcaf 100644
--- a/gcc/print-rtl.h
+++ b/gcc/print-rtl.h
@@ -36,6 +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);
+extern void print_rtx_function (FILE *file, function *fn, bool compact);
 
 #endif  // GCC_PRINT_RTL_H
-- 
1.8.5.3

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

* Re: [PATCH] Add a "compact" mode to print_rtx_function
  2016-10-12 17:17             ` [PATCH] Add a "compact" mode to print_rtx_function David Malcolm
@ 2016-10-12 17:31               ` Bernd Schmidt
  2016-10-12 20:06                 ` [PATCH] (v2) " David Malcolm
  2016-10-12 20:33                 ` [PATCH] Tweaks " David Malcolm
  0 siblings, 2 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-12 17:31 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/12/2016 07:48 PM, David Malcolm wrote:
> This patch implements a "compact" mode for print_rtx_function,
> implementing most of the ideas above.
>
> Example of output can be seen here:
>   https://dmalcolm.fedorapeople.org/gcc/2016-10-12/test-switch-compact.rtl
> which can be contrasted with the non-compact output here:
>   https://dmalcolm.fedorapeople.org/gcc/2016-10-12/test-switch-noncompact.rtl
>
> It adds the "c" prefix to the insn names, so we get "cinsn", etc.  However,
> it does lead to things like this:
>
>    (ccode_label 56 8 "")
>
> which gives me pause: would the "ccode" in "ccode_label" be confusing? (compared
> to "ccmode").  An alternative might be to have a "compact-insn-chain" vs
> "insn-chain" wrapper element, expressing that this is a compact dump.

Maybe "clabel" or something.

> OK for trunk if it passes?

I'd say yes - we're iterating and this seems to be an improvement.

> I think the only remaining item from our discussion above is what to do
> about the numbering of pseudos in the dumps (currently it just prints the regno
> unmodified).
>
> Other than that, is the resultant dump format good enough that I can start
> rewriting the RTL frontend parser, or are there other changes you'd want?

Give me a day or two to think it over, and for others to chime in. But I 
think this is reasonably close to what it should look like. Maybe empty 
edge flags don't need to be printed, and possibly there could be a more 
compact format for a large number edges like what you have for the switch?

> +  /* For insns, print the INSN_UID.
> +     In compact mode, we only print the INSN_UID of CODE_LABELs.  */
> +  if (!flag_compact || GET_CODE (in_rtx) == CODE_LABEL)
> +    if (INSN_CHAIN_CODE_P (GET_CODE (in_rtx)))

The two ifs should be merged I think.


Bernd

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

* [PATCH] (v2) Add a "compact" mode to print_rtx_function
  2016-10-12 17:31               ` Bernd Schmidt
@ 2016-10-12 20:06                 ` David Malcolm
  2016-10-13 10:21                   ` Bernd Schmidt
  2016-11-22 13:18                   ` [PATCH] (v2) Add a "compact" mode to print_rtx_function Dominik Vogt
  2016-10-12 20:33                 ` [PATCH] Tweaks " David Malcolm
  1 sibling, 2 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-12 20:06 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm

On Wed, 2016-10-12 at 19:31 +0200, Bernd Schmidt wrote:
> On 10/12/2016 07:48 PM, David Malcolm wrote:
> > This patch implements a "compact" mode for print_rtx_function,
> > implementing most of the ideas above.
> > 
> > Example of output can be seen here:
> >   https://dmalcolm.fedorapeople.org/gcc/2016-10-12/test-switch-comp
> > act.rtl
> > which can be contrasted with the non-compact output here:
> >   https://dmalcolm.fedorapeople.org/gcc/2016-10-12/test-switch-nonc
> > ompact.rtl
> > 
> > It adds the "c" prefix to the insn names, so we get "cinsn", etc. 
> >  However,
> > it does lead to things like this:
> > 
> >    (ccode_label 56 8 "")
> > 
> > which gives me pause: would the "ccode" in "ccode_label" be
> > confusing? (compared
> > to "ccmode").  An alternative might be to have a "compact-insn
> > -chain" vs
> > "insn-chain" wrapper element, expressing that this is a compact
> > dump.
> 
> Maybe "clabel" or something.

I've special-cased it to be "clabel" rather than "ccode_label".

> > OK for trunk if it passes?
> 
> I'd say yes - we're iterating and this seems to be an improvement.

It didn't pass, due to this change:

     (print_rtx_operand_code_i): When printing source locations, wrap
     xloc.file in quotes. [...snip...]

Note that this change isn't guarded by flag_compact; it affects all
dumps, which meant that this testcase stopped working:
  gcc.target/i386/vararg-loc.c
which used scan-rtl-dump to look for the insn location.

I had a look over the testsuite looking for other scan-rtl-dump
directives that could be affected by the change, and I didn't see any
though obviously I could have missed some.

The following is a revised version of the patch which updates this test case.

> > I think the only remaining item from our discussion above is what
> > to do
> > about the numbering of pseudos in the dumps (currently it just
> > prints the regno
> > unmodified).
> > 
> > Other than that, is the resultant dump format good enough that I
> > can start
> > rewriting the RTL frontend parser, or are there other changes you'd
> > want?
> 
> Give me a day or two to think it over, and for others to chime in.
> But I
> think this is reasonably close to what it should look like. Maybe
> empty
> edge flags don't need to be printed, and possibly there could be a
> more
> compact format for a large number edges like what you have for the
> switch?
> 
> > +  /* For insns, print the INSN_UID.
> > +     In compact mode, we only print the INSN_UID of CODE_LABELs. 
> >  */
> > +  if (!flag_compact || GET_CODE (in_rtx) == CODE_LABEL)
> > +    if (INSN_CHAIN_CODE_P (GET_CODE (in_rtx)))
> 
> The two ifs should be merged I think.
 
Changed in v2:
- fixes to gcc.target/i386/vararg-loc.c
- "clabel" rather than "ccode_label"
- merged the two "if"s

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.

OK for trunk?

gcc/ChangeLog:
	* function-tests.c (selftest::test_expansion_to_rtl): Add "true"
	for new "compact" param of print_rtx_function.  Check for "cinsn"
	rather than "insn".
	* print-rtl-function.c (flag_compact): New decl.
	(print_rtx_function): Add param "compact" and use it to set
	flag_compact, adding a description of the effect to the leading
	comment, and updating the example output.
	* print-rtl.c (flag_compact): New variable.
	(print_rtx_operand_code_0): Omit the JUMP_LABEL reference in compact
	mode.
	(print_rtx_operand_code_i): When printing source locations, wrap
	xloc.file in quotes.  Don't print INSN_CODEs in compact mode.
	(print_rtx_operand_code_r): Don't print regnos for hard regs and
	virtuals in compact mode.
	(print_rtx_operand_code_u): Don't print insn UIDs in compact mode,
	apart from in LABEL_REFs.
	(print_rtx_operand): In case 'w', don't print in hex in compact mode.
	Don't print basic block ids in compact mode.
	(print_rtx):  In compact mode, prefix the code of insns with "c",
	only print the INSN_UID of CODE_LABELs, and omit their LABEL_NUSES.
	* print-rtl.h (print_rtx_function): Add "compact" param.

gcc/testsuite/ChangeLog:
	* gcc.target/i386/vararg-loc.c: Update for quoting of xloc.file
	in INSN_LOCATION.
---
 gcc/function-tests.c                       |  4 +-
 gcc/print-rtl-function.c                   | 76 +++++++++++++++++-------------
 gcc/print-rtl.c                            | 73 +++++++++++++++++++++-------
 gcc/print-rtl.h                            |  2 +-
 gcc/testsuite/gcc.target/i386/vararg-loc.c |  6 +--
 5 files changed, 107 insertions(+), 54 deletions(-)

diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index 049a07f9..b0c44cf 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -648,7 +648,7 @@ test_expansion_to_rtl ()
   /* Verify that print_rtl_function is sane.  */
   named_temp_file tmp_out (".rtl");
   FILE *outfile = fopen (tmp_out.get_filename (), "w");
-  print_rtx_function (outfile, fun);
+  print_rtx_function (outfile, fun, true);
   fclose (outfile);
 
   char *dump = read_file (SELFTEST_LOCATION, tmp_out.get_filename ());
@@ -656,7 +656,7 @@ test_expansion_to_rtl ()
   ASSERT_STR_CONTAINS (dump, "  (insn-chain\n");
   ASSERT_STR_CONTAINS (dump, "    (block 2\n");
   ASSERT_STR_CONTAINS (dump, "      (edge-from entry (flags \"FALLTHRU\"))\n");
-  ASSERT_STR_CONTAINS (dump, "      (insn "); /* ...etc.  */
+  ASSERT_STR_CONTAINS (dump, "      (cinsn "); /* ...etc.  */
   ASSERT_STR_CONTAINS (dump, "      (edge-to exit (flags \"FALLTHRU\"))\n");
   ASSERT_STR_CONTAINS (dump, "    ) ;; block 2\n");
   ASSERT_STR_CONTAINS (dump, "  ) ;; insn-chain\n");
diff --git a/gcc/print-rtl-function.c b/gcc/print-rtl-function.c
index 4f9b4ef..90a0ff7 100644
--- a/gcc/print-rtl-function.c
+++ b/gcc/print-rtl-function.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "emit-rtl.h"
 
+extern bool flag_compact;
+
 /* Print an "(edge-from)" or "(edge-to)" directive describing E
    to OUTFILE.  */
 
@@ -126,55 +128,63 @@ can_have_basic_block_p (const rtx_insn *insn)
    the basic blocks of insns in the chain, wrapping those that are within
    blocks within "(block)" directives.
 
-   Example output:
+   If COMPACT, then instructions are printed in a compact form:
+   - INSN_UIDs are omitted, except for jumps and CODE_LABELs,
+   - INSN_CODEs are omitted,
+   - register numbers are omitted for hard and virtual regs
+   - insn names are prefixed with "c" (e.g. "cinsn", "cnote", etc)
+
+   Example output (with COMPACT==true):
 
    (function "times_two"
      (insn-chain
-       (note 1 0 4 (nil) NOTE_INSN_DELETED)
+       (cnote NOTE_INSN_DELETED)
        (block 2
 	 (edge-from entry (flags "FALLTHRU"))
-	 (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))
+	 (cnote [bb 2] NOTE_INSN_BASIC_BLOCK)
+	 (cinsn (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+			       (const_int -4)) [1 i+0 S4 A32])
+		       (reg:SI di [ i ])) "t.c":2
+		   (nil))
+	 (cnote NOTE_INSN_FUNCTION_BEG)
+	 (cinsn (set (reg:SI 89)
+		       (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+			       (const_int -4)) [1 i+0 S4 A32])) "t.c":3
+		   (nil))
+	 (cinsn (parallel [
+			   (set (reg:SI 87 [ _2 ])
+			       (ashift:SI (reg:SI 89)
+				   (const_int 1)))
+			   (clobber (reg:CC flags))
+		       ]) "t.c":3
+		   (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+				   (const_int -4)) [1 i+0 S4 A32])
+			   (const_int 1))
+		       (nil)))
+	 (cinsn (set (reg:SI 88 [ <retval> ])
+		       (reg:SI 87 [ _2 ])) "t.c":3
+		   (nil))
+	 (cinsn (set (reg/i:SI ax)
+		       (reg:SI 88 [ <retval> ])) "t.c":4
+		   (nil))
+	 (cinsn (use (reg/i:SI ax)) "t.c":4
+		   (nil))
 	 (edge-to exit (flags "FALLTHRU"))
        ) ;; block 2
      ) ;; insn-chain
      (crtl
        (return_rtx
-	  (reg/i:SI 0 ax)
+	 (reg/i:SI ax)
        ) ;; return_rtx
      ) ;; crtl
    ) ;; function "times_two"
 */
 
 DEBUG_FUNCTION void
-print_rtx_function (FILE *outfile, function *fn)
+print_rtx_function (FILE *outfile, function *fn, bool compact)
 {
+  flag_compact = compact;
+
   tree fdecl = fn->decl;
 
   const char *dname = lang_hooks.decl_printable_name (fdecl, 2);
@@ -210,4 +220,6 @@ print_rtx_function (FILE *outfile, function *fn)
   fprintf (outfile, "  ) ;; crtl\n");
 
   fprintf (outfile, ") ;; function \"%s\"\n", dname);
+
+  flag_compact = false;
 }
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 29e8ee2..f114cb4 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -60,6 +60,13 @@ static int indent;
 
 static bool in_call_function_usage;
 
+/* If true, use compact dump format:
+   - INSN_UIDs are omitted, except for jumps and CODE_LABELs,
+   - INSN_CODEs are omitted,
+   - register numbers are omitted for hard and virtual regs
+   - insn names are prefixed with "c" (e.g. "cinsn", "cnote", etc).  */
+bool flag_compact;
+
 static void print_rtx (const_rtx);
 
 /* String printed at beginning of each RTL when it is dumped.
@@ -176,7 +183,8 @@ print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  break;
 	}
     }
-  else if (idx == 7 && JUMP_P (in_rtx) && JUMP_LABEL (in_rtx) != NULL)
+  else if (idx == 7 && JUMP_P (in_rtx) && JUMP_LABEL (in_rtx) != NULL
+	   && !flag_compact)
     {
       /* Output the JUMP_LABEL reference.  */
       fprintf (outfile, "\n%s%*s -> ", print_rtx_head, indent * 2, "");
@@ -284,7 +292,7 @@ print_rtx_operand_code_i (const_rtx in_rtx, int idx)
       if (INSN_HAS_LOCATION (in_insn))
 	{
 	  expanded_location xloc = insn_location (in_insn);
-	  fprintf (outfile, " %s:%i", xloc.file, xloc.line);
+	  fprintf (outfile, " \"%s\":%i", xloc.file, xloc.line);
 	}
 #endif
     }
@@ -335,6 +343,13 @@ print_rtx_operand_code_i (const_rtx in_rtx, int idx)
       const char *name;
       int is_insn = INSN_P (in_rtx);
 
+      /* Don't print INSN_CODEs in compact mode.  */
+      if (flag_compact && is_insn && &INSN_CODE (in_rtx) == &XINT (in_rtx, idx))
+	{
+	  sawclose = 0;
+	  return;
+	}
+
       if (flag_dump_unnumbered
 	  && (is_insn || NOTE_P (in_rtx)))
 	fputc ('#', outfile);
@@ -358,26 +373,28 @@ print_rtx_operand_code_r (const_rtx in_rtx)
   unsigned int regno = REGNO (in_rtx);
 
 #ifndef GENERATOR_FILE
+  /* For hard registers and virtuals, always print the
+     regno, except in compact mode.  */
+  if (regno <= LAST_VIRTUAL_REGISTER && !flag_compact)
+    fprintf (outfile, " %d", regno);
   if (regno < FIRST_PSEUDO_REGISTER)
-    fprintf (outfile, " %d %s", regno, reg_names[regno]);
+    fprintf (outfile, " %s", reg_names[regno]);
   else if (regno <= LAST_VIRTUAL_REGISTER)
     {
       if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
-	fprintf (outfile, " %d virtual-incoming-args", regno);
+	fprintf (outfile, " virtual-incoming-args");
       else if (regno == VIRTUAL_STACK_VARS_REGNUM)
-	fprintf (outfile, " %d virtual-stack-vars", regno);
+	fprintf (outfile, " virtual-stack-vars");
       else if (regno == VIRTUAL_STACK_DYNAMIC_REGNUM)
-	fprintf (outfile, " %d virtual-stack-dynamic", regno);
+	fprintf (outfile, " virtual-stack-dynamic");
       else if (regno == VIRTUAL_OUTGOING_ARGS_REGNUM)
-	fprintf (outfile, " %d virtual-outgoing-args", regno);
+	fprintf (outfile, " virtual-outgoing-args");
       else if (regno == VIRTUAL_CFA_REGNUM)
-	fprintf (outfile, " %d virtual-cfa", regno);
+	fprintf (outfile, " virtual-cfa");
       else if (regno == VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM)
-	fprintf (outfile, " %d virtual-preferred-stack-boundary",
-		 regno);
+	fprintf (outfile, " virtual-preferred-stack-boundary");
       else
-	fprintf (outfile, " %d virtual-reg-%d", regno,
-		 regno-FIRST_VIRTUAL_REGISTER);
+	fprintf (outfile, " virtual-reg-%d", regno-FIRST_VIRTUAL_REGISTER);
     }
   else
 #endif
@@ -410,6 +427,10 @@ print_rtx_operand_code_r (const_rtx in_rtx)
 static void
 print_rtx_operand_code_u (const_rtx in_rtx, int idx)
 {
+  /* Don't print insn UIDs in compact mode, apart from in LABEL_REFs.  */
+  if (flag_compact && GET_CODE (in_rtx) != LABEL_REF)
+    return;
+
   if (XEXP (in_rtx, idx) != NULL)
     {
       rtx sub = XEXP (in_rtx, idx);
@@ -492,7 +513,7 @@ print_rtx_operand (const_rtx in_rtx, int idx)
       if (! flag_simple)
 	fprintf (outfile, " ");
       fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, XWINT (in_rtx, idx));
-      if (! flag_simple)
+      if (! flag_simple && !flag_compact)
 	fprintf (outfile, " [" HOST_WIDE_INT_PRINT_HEX "]",
 		 (unsigned HOST_WIDE_INT) XWINT (in_rtx, idx));
       break;
@@ -533,6 +554,9 @@ print_rtx_operand (const_rtx in_rtx, int idx)
       break;
 
     case 'B':
+      /* Don't print basic block ids in compact mode.  */
+      if (flag_compact)
+	break;
 #ifndef GENERATOR_FILE
       if (XBBDEF (in_rtx, idx))
 	fprintf (outfile, " %i", XBBDEF (in_rtx, idx)->index);
@@ -575,7 +599,20 @@ print_rtx (const_rtx in_rtx)
     }
 
   /* Print name of expression code.  */
-  if (flag_simple && CONST_INT_P (in_rtx))
+
+  /* In compact mode, prefix the code of insns with "c",
+     giving "cinsn", "cnote" etc.  */
+  if (flag_compact && is_a <const rtx_insn *, const struct rtx_def> (in_rtx))
+    {
+      /* "ccode_label" is slightly awkward, so special-case it as
+	 just "clabel".  */
+      rtx_code code = GET_CODE (in_rtx);
+      if (code == CODE_LABEL)
+	fprintf (outfile, "(clabel");
+      else
+	fprintf (outfile, "(c%s", GET_RTX_NAME (code));
+    }
+  else if (flag_simple && CONST_INT_P (in_rtx))
     fputc ('(', outfile);
   else
     fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx)));
@@ -639,7 +676,10 @@ print_rtx (const_rtx in_rtx)
     idx = 5;
 #endif
 
-  if (INSN_CHAIN_CODE_P (GET_CODE (in_rtx)))
+  /* For insns, print the INSN_UID.
+     In compact mode, we only print the INSN_UID of CODE_LABELs.  */
+  if (INSN_CHAIN_CODE_P (GET_CODE (in_rtx))
+      && (!flag_compact || GET_CODE (in_rtx) == CODE_LABEL))
     {
       if (flag_dump_unnumbered)
 	fprintf (outfile, " #");
@@ -704,7 +744,8 @@ print_rtx (const_rtx in_rtx)
 #endif
 
     case CODE_LABEL:
-      fprintf (outfile, " [%d uses]", LABEL_NUSES (in_rtx));
+      if (!flag_compact)
+	fprintf (outfile, " [%d uses]", LABEL_NUSES (in_rtx));
       switch (LABEL_KIND (in_rtx))
 	{
 	  case LABEL_NORMAL: break;
diff --git a/gcc/print-rtl.h b/gcc/print-rtl.h
index 9cad683..7a1dcaf 100644
--- a/gcc/print-rtl.h
+++ b/gcc/print-rtl.h
@@ -36,6 +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);
+extern void print_rtx_function (FILE *file, function *fn, bool compact);
 
 #endif  // GCC_PRINT_RTL_H
diff --git a/gcc/testsuite/gcc.target/i386/vararg-loc.c b/gcc/testsuite/gcc.target/i386/vararg-loc.c
index 8134ba8..f46ac57 100644
--- a/gcc/testsuite/gcc.target/i386/vararg-loc.c
+++ b/gcc/testsuite/gcc.target/i386/vararg-loc.c
@@ -22,6 +22,6 @@ f (int a, ...)			/* 8.  */
   return sum;
 }
 
-/* { dg-final { scan-rtl-dump-not "vararg-loc\\.c:\[6789\] " "final" } } */
-/* { dg-final { scan-rtl-dump "vararg-loc\\.c:18 " "final" } } */
-/* { dg-final { scan-rtl-dump "vararg-loc\\.c:20 " "final" } } */
+/* { dg-final { scan-rtl-dump-not "vararg-loc\\.c.:\[6789\] " "final" } } */
+/* { dg-final { scan-rtl-dump "vararg-loc\\.c.:18 " "final" } } */
+/* { dg-final { scan-rtl-dump "vararg-loc\\.c.:20 " "final" } } */
-- 
1.8.5.3

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

* [PATCH] Tweaks to print_rtx_function
  2016-10-12 17:31               ` Bernd Schmidt
  2016-10-12 20:06                 ` [PATCH] (v2) " David Malcolm
@ 2016-10-12 20:33                 ` David Malcolm
  2016-10-13 10:24                   ` Bernd Schmidt
  1 sibling, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-12 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: Bernd Schmidt, David Malcolm

On Wed, 2016-10-12 at 19:31 +0200, Bernd Schmidt wrote:
> On 10/12/2016 07:48 PM, David Malcolm wrote:

[...snip...]

> > I think the only remaining item from our discussion above is what
> > to do
> > about the numbering of pseudos in the dumps (currently it just
> > prints the regno
> > unmodified).
> >
> > Other than that, is the resultant dump format good enough that I
> > can start
> > rewriting the RTL frontend parser, or are there other changes you'd
> > want?
>
> Give me a day or two to think it over, and for others to chime in.
> But I
> think this is reasonably close to what it should look like. Maybe
> empty
> edge flags don't need to be printed, and possibly there could be a
> more
> compact format for a large number edges like what you have for the
> switch?

[...snip...]

This patch implements:
* the renumbering of non-virtual pseudos, using
  LAST_VIRTUAL_REGISTER + 1 as a base.
* omitting the edge "(flags)" directive if there aren't any

Bootstrap & regrtest in progress.

OK for trunk if they pass?

gcc/ChangeLog:
	* print-rtl-function.c (print_edge): Omit "(flags)" when none are
	set.
	* print-rtl.c (print_rtx_operand_code_r): In compact mode, print
	pseudos offset by (LAST_VIRTUAL_REGISTER + 1), so that the first
	non-virtual pseudo is 0.
---
 gcc/print-rtl-function.c | 13 +++++++++----
 gcc/print-rtl.c          |  8 ++++++++
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/gcc/print-rtl-function.c b/gcc/print-rtl-function.c
index 90a0ff7..770cee3 100644
--- a/gcc/print-rtl-function.c
+++ b/gcc/print-rtl-function.c
@@ -59,9 +59,11 @@ print_edge (FILE *outfile, edge e, bool from)
 
   /* Express edge flags as a string with " | " separator.
      e.g. (flags "FALLTHRU | DFS_BACK").  */
-  fprintf (outfile, " (flags \"");
-  bool seen_flag = false;
-#define DEF_EDGE_FLAG(NAME,IDX) \
+  if (e->flags)
+    {
+      fprintf (outfile, " (flags \"");
+      bool seen_flag = false;
+#define DEF_EDGE_FLAG(NAME,IDX)			\
   do {						\
     if (e->flags & EDGE_##NAME)			\
       {						\
@@ -74,7 +76,10 @@ print_edge (FILE *outfile, edge e, bool from)
 #include "cfg-flags.def"
 #undef DEF_EDGE_FLAG
 
-  fprintf (outfile, "\"))\n");
+      fprintf (outfile, "\")");
+    }
+
+  fprintf (outfile, ")\n");
 }
 
 /* If BB is non-NULL, print the start of a "(block)" directive for it
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index f114cb4..86816b5 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -400,6 +400,14 @@ print_rtx_operand_code_r (const_rtx in_rtx)
 #endif
     if (flag_dump_unnumbered && is_insn)
       fputc ('#', outfile);
+    else if (flag_compact)
+      {
+	/* In compact mode, print pseudos offset by
+	   (LAST_VIRTUAL_REGISTER + 1), so that the first non-virtual pseudo
+	   is dumped as 0.  */
+	gcc_assert (regno > LAST_VIRTUAL_REGISTER);
+	fprintf (outfile, " %d", regno - (LAST_VIRTUAL_REGISTER + 1));
+      }
     else
       fprintf (outfile, " %d", regno);
 
-- 
1.8.5.3

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

* Re: [PATCH 01/16] read-md.c: Add various cleanups to ~rtx_reader
  2016-10-11 15:15     ` David Malcolm
@ 2016-10-12 21:57       ` Richard Sandiford
  2016-10-14 17:45         ` [PATCH] read-md.c: Move various state to within class rtx_reader David Malcolm
  0 siblings, 1 reply; 96+ messages in thread
From: Richard Sandiford @ 2016-10-12 21:57 UTC (permalink / raw)
  To: David Malcolm; +Cc: Bernd Schmidt, gcc-patches

Sorry, haven't had time to read the full series yet, but:

David Malcolm <dmalcolm@redhat.com> writes:
> On Wed, 2016-10-05 at 17:51 +0200, Bernd Schmidt wrote:
>> On 10/05/2016 06:14 PM, David Malcolm wrote:
>> > The selftests for the RTL frontend require supporting multiple
>> > reader instances being alive one after another in-process, so
>> > this lack of cleanup would become a leak.
>> 
>> > +  /* Initialize global data.  */
>> > +  obstack_init (&string_obstack);
>> > +  ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p,
>> > 0);
>> > +  obstack_init (&ptr_loc_obstack);
>> > +  joined_conditions = htab_create (161, leading_ptr_hash,
>> > leading_ptr_eq_p, 0);
>> > +  obstack_init (&joined_conditions_obstack);
>> > +  md_constants = htab_create (31, leading_string_hash,
>> > +			      leading_string_eq_p, (htab_del) 0);
>> > +  enum_types = htab_create (31, leading_string_hash,
>> > +			    leading_string_eq_p, (htab_del) 0);
>> > +
>> > +  /* Unlock the stdio streams.  */
>> > +  unlock_std_streams ();
>> 
>> Hmm, but these are global statics. Shouldn't they first be moved to 
>> become class members?
>
> [CCing Richard Sandiford]
>
> I tried to move these into class rtx_reader, but doing so rapidly
> became quite invasive, with many of functions in the gen* tools
> becoming methods.

Is that just to avoid introducing explicit references to the global
rtx_reader object in the gen* tools?  If so, then TBH adding those
references sound better to me than tying generator-specific functions
to the rtx reader (not least because most of them do more than just
read rtl).

> Arguably that would be a good thing, but there are a couple of issues:
>
> (a) some of these functions take "vec" arguments; moving them from
> static functions to being class methods requires that vec.h has been
> included when the relevant class decl is parsed.

I don't think including vec.h more often should be a blocker though. :-)

> (b) rtx_reader turns into a bug dumping ground of methods, for the
> union of all of the various gen* tools.
>
> One way to alleviate these issues would be to do the split of
> rtx_reader into base_rtx_reader vs rtx_reader from patch 9 of the kit:
>   https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00273.html
> and perhaps to split out part of read-md.h into a new read-rtl.h.
>
> Before I reorganize the patches, does this approach sound reasonable?
>
> Alternatively, a less invasive approach is to have an accessor for
> these fields, so that things using them can get at them via the
> rtx_reader_ptr singleton e.g.:
>
> void
> grow_string_obstack (char ch)
> {
>    obstack_1grow (rtx_reader_ptr->get_string_obstack (), ch);
> }
>
> and similar.

I think it's OK for the generators to refer rtx_reader_ptr directly.
Obviously that makes the patches more invasive, but hopefully the
extra changes are mechanical.

Thanks,
Richard

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

* Re: [PATCH] (v2) Add a "compact" mode to print_rtx_function
  2016-10-12 20:06                 ` [PATCH] (v2) " David Malcolm
@ 2016-10-13 10:21                   ` Bernd Schmidt
  2016-10-13 15:22                     ` [PATCH] Omit INSN_LOCATION from compact dumps David Malcolm
  2016-11-22 13:18                   ` [PATCH] (v2) Add a "compact" mode to print_rtx_function Dominik Vogt
  1 sibling, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-13 10:21 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/12/2016 10:37 PM, David Malcolm wrote:
> It didn't pass, due to this change:
>
>      (print_rtx_operand_code_i): When printing source locations, wrap
>      xloc.file in quotes. [...snip...]
[...]
> The following is a revised version of the patch which updates this test case.

Also ok. This reminds me, wrapping the filename in quotes was a side 
issue - what I was really hoping for was to have testcases without this 
visual clutter unless they wanted to explicitly test functionality 
related to it.


Bernd

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

* Re: [PATCH] Tweaks to print_rtx_function
  2016-10-12 20:33                 ` [PATCH] Tweaks " David Malcolm
@ 2016-10-13 10:24                   ` Bernd Schmidt
  2016-10-13 14:08                     ` David Malcolm
  0 siblings, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-13 10:24 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/12/2016 11:04 PM, David Malcolm wrote:
>
> This patch implements:
> * the renumbering of non-virtual pseudos, using
>   LAST_VIRTUAL_REGISTER + 1 as a base.
> * omitting the edge "(flags)" directive if there aren't any
>
> Bootstrap & regrtest in progress.
>
> OK for trunk if they pass?

I tend to think probably yes. Let's say ok if I don't object by tomorrow 
:) I'm still wondering whether we want to use some sort of prefix like 
$p or %p which is distinct from any hard register name for clarity.


Bernd

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

* Re: [PATCH] Add "__RTL" to cc1 (v2)
  2016-10-07 15:27     ` [PATCH] Add "__RTL" to cc1 (v2) David Malcolm
@ 2016-10-13 13:49       ` Richard Biener
  2016-10-13 13:52         ` Bernd Schmidt
  2016-10-14 19:23         ` David Malcolm
  0 siblings, 2 replies; 96+ messages in thread
From: Richard Biener @ 2016-10-13 13:49 UTC (permalink / raw)
  To: David Malcolm; +Cc: Joseph Myers, GCC Patches

On Fri, Oct 7, 2016 at 5:58 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> On Wed, 2016-10-05 at 16:09 +0000, Joseph Myers wrote:
>> On Wed, 5 Oct 2016, David Malcolm wrote:
>>
>> > @@ -1752,6 +1759,35 @@ c_parser_declaration_or_fndef (c_parser
>> > *parser, bool fndef_ok,
>> >        c_parser_skip_to_end_of_block_or_statement (parser);
>> >        return;
>> >      }
>> > +
>> > +  if (c_parser_next_token_is (parser, CPP_KEYWORD))
>> > +    {
>> > +      c_token *kw_token = c_parser_peek_token (parser);
>> > +      if (kw_token->keyword == RID_RTL)
>>
>> if (c_parser_next_token_is_keyword (parser, RID_RTL))
>>
>> You're missing an update to the comment above this function to show
>> what
>> the new syntax is.
>
> Thanks.  Here's an updated version of the patch which fixes that,
> along with some other fixes:
> * Use c_parser_next_token_is_keyword.
> * Removed a stray "FIXME".
> * Removed some debug code.
> * Add more comments
> * Fixed a typo in the ChangeLog ("__RID" -> "__RTL")
>
> Blurb from original version:
>
> This patch implements Richi's idea of having a custom __RTL marker
> in C function definitions, to indicate that the body of the function
> is to be parsed as RTL, rather than C:
>
> int __RTL test_fn_1 (int i)
> {
>  (function "times_two"
>    (insn-chain
>      (note 1 0 4 (nil) NOTE_INSN_DELETED)
>      ;; etc
>    ) ;; insn-chain
>    (crtl
>      (return_rtx
>        (reg/i:SI 0 ax)
>      ) ;; return_rtx
>    ) ;; crtl
>   ) ;; function
> }
>
> This allows for decls and types to be declared in C, and to use
> the function decl from the C frontend.
>
> I added support for running a single pass by giving __RTL an optional
> parameter (the name of the pass).  For example:

So what's the default behavior?

> int __RTL ("rtl-dfinit") test_fn_2 (int i)
> {
>  (function "times_two"
>    (insn-chain
>      (note 1 0 4 (nil) NOTE_INSN_DELETED)
>      ;; etc
>    ) ;; insn-chain
>    (crtl
>      (return_rtx
>        (reg/i:SI 0 ax)
>      ) ;; return_rtx
>    ) ;; crtl
>   ) ;; function
> }

Does it really run a single pass only?  Thus you can't do a { dg-do run } test
with __RTL?  The GIMPLE FE has a __GIMPLE (starts-with: "pass") thing
starting from a specific pass but going all the way to assembly output.

It looks like your run-one-rtl-pass thingy is directly invoked from
the "frontend"
rather than passing down everything to the middle-end?

Richard.

> The top-level "function" directive is rather redundant; perhaps it should
> be omitted?  This would give e.g.:
>
> int __RTL ("rtl-dfinit") test_fn_3 (int i)
> {
>    (insn-chain
>      (note 1 0 4 (nil) NOTE_INSN_DELETED)
>      ;; etc
>    ) ;; insn-chain
>    (crtl
>      (return_rtx
>        (reg/i:SI 0 ax)
>      ) ;; return_rtx
>    ) ;; crtl
> }
>
> (Though maybe we want to keep it as a place to hold top-level metadata)
>
> gcc/c-family/ChangeLog:
>         * c-common.c (c_common_reswords): Add "__RTL".
>         * c-common.h (enum rid): Add RID_RTL.
>
> gcc/c/ChangeLog:
>         * c-parser.c: Include "read-rtl-function.h" and
>         "run-one-rtl-pass.h".
>         (c_parser_declaration_or_fndef): In the "GNU extensions" part of
>         the leading comment, add an alternate production for
>         "function-definition", along with new "rtl-body-specifier" and
>         "rtl-body-pass-specifier" productions.  Handle "__RTL" by calling
>         c_parser_parse_rtl_body.  Convert a timevar_push/pop pair
>         to an auto_timevar, to cope with early exit.
>         (c_parser_parse_rtl_body): New function.
>
> gcc/ChangeLog:
>         * read-md.c (base_rtx_reader::read_char): Support filtering
>         the input to a subset of line numbers.
>         (base_rtx_reader::base_rtx_reader): Initialize fields
>         m_first_line and m_last_line.
>         (base_rtx_reader::read_file_fragment): New method.
>         * read-md.h (base_rtx_reader::read_file_fragment): New decl.
>         (base_rtx_reader::m_first_line): New field.
>         (base_rtx_reader::m_last_line): New field.
>         * read-rtl-function.c (function_reader::create_function): Only create
>         cfun if it doesn't already exist.
>         (read_rtl_function_body_from_file_range): New function.
>         * read-rtl-function.h (read_rtl_function_body_from_file_range):
>         New decl.
>
> gcc/testsuite/ChangeLog:
>         * rtl.dg/rtl.exp: Add .c files below rtl.dg to "tests".
>         * rtl.dg/x86_64/different-structs.c: New file.
>         * rtl.dg/x86_64/test-return-const.c.after-expand.c: New file.
>         * rtl.dg/x86_64/test-return-const.c.before-fwprop.c: New file.
>         * rtl.dg/x86_64/test-rtl.c: New file.
>         * rtl.dg/x86_64/times-two.c.after-expand.c: New file.
>         * rtl.dg/x86_64/times-two.c.before-df.c: New file.
> ---
>  gcc/c-family/c-common.c                            |   1 +
>  gcc/c-family/c-common.h                            |   3 +
>  gcc/c/c-parser.c                                   | 113 ++++++++++++++++++++-
>  gcc/read-md.c                                      |  34 ++++++-
>  gcc/read-md.h                                      |   7 ++
>  gcc/read-rtl-function.c                            |  78 ++++++++++----
>  gcc/read-rtl-function.h                            |   3 +
>  gcc/testsuite/rtl.dg/rtl.exp                       |   4 +-
>  gcc/testsuite/rtl.dg/x86_64/different-structs.c    | 101 ++++++++++++++++++
>  .../x86_64/test-return-const.c.after-expand.c      |  23 +++++
>  .../x86_64/test-return-const.c.before-fwprop.c     |  27 +++++
>  gcc/testsuite/rtl.dg/x86_64/test-rtl.c             |  95 +++++++++++++++++
>  .../rtl.dg/x86_64/times-two.c.after-expand.c       |  40 ++++++++
>  .../rtl.dg/x86_64/times-two.c.before-df.c          |  57 +++++++++++
>  14 files changed, 565 insertions(+), 21 deletions(-)
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/different-structs.c
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-rtl.c
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
>
> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
> index 491c637..ecef32b 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -524,6 +524,7 @@ const struct c_common_resword c_common_reswords[] =
>    { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
>    { "__volatile",      RID_VOLATILE,   0 },
>    { "__volatile__",    RID_VOLATILE,   0 },
> +  { "__RTL",           RID_RTL,        0 },
>    { "alignas",         RID_ALIGNAS,    D_CXXONLY | D_CXX11 | D_CXXWARN },
>    { "alignof",         RID_ALIGNOF,    D_CXXONLY | D_CXX11 | D_CXXWARN },
>    { "asm",             RID_ASM,        D_ASM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index c88619b..e19751e 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -118,6 +118,9 @@ enum rid
>
>    RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
>
> +  /* "__RTL", for the RTL-parsing extension to the C frontend.  */
> +  RID_RTL,
> +
>    /* C11 */
>    RID_ALIGNAS, RID_GENERIC,
>
> diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
> index 6bc42da..693d1bd 100644
> --- a/gcc/c/c-parser.c
> +++ b/gcc/c/c-parser.c
> @@ -59,6 +59,8 @@ along with GCC; see the file COPYING3.  If not see
>  #include "gimple-expr.h"
>  #include "context.h"
>  #include "gcc-rich-location.h"
> +#include "read-rtl-function.h"
> +#include "run-one-rtl-pass.h"
>
>  /* We need to walk over decls with incomplete struct/union/enum types
>     after parsing the whole translation unit.
> @@ -1421,6 +1423,9 @@ static tree c_parser_array_notation (location_t, c_parser *, tree, tree);
>  static tree c_parser_cilk_clause_vectorlength (c_parser *, tree, bool);
>  static void c_parser_cilk_grainsize (c_parser *, bool *);
>
> +static void c_parser_parse_rtl_body (c_parser *parser,
> +                                    const char *single_pass_name);
> +
>  /* Parse a translation unit (C90 6.7, C99 6.9).
>
>     translation-unit:
> @@ -1624,6 +1629,16 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
>       declaration-specifiers declarator declaration-list[opt]
>         compound-statement
>
> +   function-definition:
> +     declaration-specifiers rtl-body-specifier declarator declaration-list[opt]
> +       compound-statement
> +
> +   rtl-body-specifier:
> +     __RTL rtl-body-pass-specifier[opt]
> +
> +   rtl-body-pass-specifier:
> +     ( string )
> +
>     attribute ;
>
>     Objective-C:
> @@ -1668,6 +1683,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>    tree all_prefix_attrs;
>    bool diagnosed_no_specs = false;
>    location_t here = c_parser_peek_token (parser)->location;
> +  bool rtl_body_p = false;
> +  const char *single_pass_name = NULL;
>
>    if (static_assert_ok
>        && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
> @@ -1752,6 +1769,33 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>        c_parser_skip_to_end_of_block_or_statement (parser);
>        return;
>      }
> +
> +  /* Handle GNU extension rtl-body-specifier by detecting "__RTL".  */
> +  if (c_parser_next_token_is_keyword (parser, RID_RTL))
> +    {
> +      rtl_body_p = true;
> +      c_parser_consume_token (parser);
> +
> +      /* Handle the optional rtl-body-pass-specifier: parens wrapping
> +        a string, giving a pass name.  */
> +      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
> +       {
> +         c_parser_consume_token (parser);
> +         c_token *tok = c_parser_peek_token (parser);
> +         if (tok->type != CPP_STRING)
> +           {
> +             c_parser_error (parser, "expected string");
> +             c_parser_skip_to_end_of_block_or_statement (parser);
> +             return;
> +           }
> +         gcc_assert (TREE_CODE (tok->value) == STRING_CST);
> +         single_pass_name = TREE_STRING_POINTER (tok->value);
> +         c_parser_consume_token (parser);
> +
> +         c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
> +       }
> +    }
> +
>    finish_declspecs (specs);
>    bool auto_type_p = specs->typespec_word == cts_auto_type;
>    if (c_parser_next_token_is (parser, CPP_SEMICOLON))
> @@ -2146,7 +2190,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>          tv = TV_PARSE_INLINE;
>        else
>          tv = TV_PARSE_FUNC;
> -      timevar_push (tv);
> +      auto_timevar at (g_timer, tv);
>
>        /* Parse old-style parameter declarations.  ??? Attributes are
>          not allowed to start declaration specifiers here because of a
> @@ -2173,6 +2217,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>         c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
>        DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
>         = c_parser_peek_token (parser)->location;
> +
> +      /* If we had an rtl-body-specifier, use the RTL parser now,
> +        consuming the function body.  */
> +      if (rtl_body_p)
> +       {
> +         c_parser_parse_rtl_body (parser, single_pass_name);
> +         return;
> +       }
> +
>        fnbody = c_parser_compound_statement (parser);
>        if (flag_cilkplus && contains_array_notation_expr (fnbody))
>         fnbody = expand_array_notation_exprs (fnbody);
> @@ -2195,7 +2248,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>           finish_function ();
>         }
>
> -      timevar_pop (tv);
>        break;
>      }
>  }
> @@ -18313,4 +18365,61 @@ c_parser_array_notation (location_t loc, c_parser *parser, tree initial_index,
>    return value_tree;
>  }
>
> +/* Parse the body of a function declaration marked with "__RTL".
> +
> +   The RTL parser works on the level of characters read from a
> +   FILE *, whereas c_parser works at the level of tokens.
> +   Square this circle by consuming all of the tokens up to and
> +   including the closing brace, recording the start/end of the RTL
> +   fragment, and reopening the file and re-reading the relevant
> +   lines within the RTL parser.
> +
> +   This requires the opening and closing braces of the C function
> +   to be on separate lines from the RTL they wrap.  */
> +
> +void
> +c_parser_parse_rtl_body (c_parser *parser, const char *single_pass_name)
> +{
> +  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
> +    return;
> +
> +  location_t start_loc = c_parser_peek_token (parser)->location;
> +
> +  /* Consume all tokens, up to the closing brace, handling
> +     matching pairs of braces in the rtl dump.  */
> +  int num_open_braces = 1;
> +  while (1)
> +    {
> +      switch (c_parser_peek_token (parser)->type)
> +       {
> +       case CPP_OPEN_BRACE:
> +         num_open_braces++;
> +         break;
> +       case CPP_CLOSE_BRACE:
> +         if (--num_open_braces == 0)
> +           goto found_closing_brace;
> +         break;
> +       default:
> +         break;
> +       }
> +      c_parser_consume_token (parser);
> +    }
> +
> + found_closing_brace:
> +  /* At the closing brace; record its location.  */
> +  location_t end_loc = c_parser_peek_token (parser)->location;
> +
> +  /* Consume the closing brace.  */
> +  c_parser_consume_token (parser);
> +
> +  /* Invoke the RTL parser.  */
> +  if (!read_rtl_function_body_from_file_range (start_loc, end_loc))
> +    return;
> +
> + /*  If -fsingle-pass=PASS_NAME was provided, locate and run PASS_NAME
> +      on cfun, as created above.  */
> +  if (single_pass_name)
> +    run_one_rtl_pass_by_name (single_pass_name);
> +}
> +
>  #include "gt-c-c-parser.h"
> diff --git a/gcc/read-md.c b/gcc/read-md.c
> index be55777..e713466 100644
> --- a/gcc/read-md.c
> +++ b/gcc/read-md.c
> @@ -419,6 +419,16 @@ base_rtx_reader::read_char (void)
>    else
>      m_read_md_colno++;
>
> +  /* If we're filtering lines, treat everything outside the
> +     range of interest as a space.  */
> +  if (m_first_line && m_last_line)
> +    {
> +      if (m_read_md_lineno < m_first_line)
> +       return ' ';
> +      if (m_read_md_lineno > m_last_line)
> +       return EOF;
> +    }
> +
>    return ch;
>  }
>
> @@ -1000,7 +1010,9 @@ base_rtx_reader::base_rtx_reader ()
>    m_read_md_lineno (0),
>    m_read_md_colno (0),
>    m_first_dir_md_include (NULL),
> -  m_last_dir_md_include_ptr (&m_first_dir_md_include)
> +  m_last_dir_md_include_ptr (&m_first_dir_md_include),
> +  m_first_line (0),
> +  m_last_line (0)
>  {
>    /* Set the global singleton pointer.  */
>    base_rtx_reader_ptr = this;
> @@ -1307,6 +1319,26 @@ base_rtx_reader::read_md_files (int argc, const char **argv,
>    return !have_error;
>  }
>
> +/* Read FILENAME, filtering to just the given lines.  */
> +
> +bool
> +base_rtx_reader::read_file_fragment (const char *filename,
> +                                    int first_line,
> +                                    int last_line)
> +{
> +  m_read_md_filename = filename;
> +  m_read_md_file = fopen (m_read_md_filename, "r");
> +  if (m_read_md_file == 0)
> +    {
> +      perror (m_read_md_filename);
> +      return false;
> +    }
> +  m_first_line = first_line;
> +  m_last_line = last_line;
> +  handle_toplevel_file ();
> +  return !have_error;
> +}
> +
>  /* class noop_reader : public base_rtx_reader */
>
>  /* A dummy implementation which skips unknown directives.  */
> diff --git a/gcc/read-md.h b/gcc/read-md.h
> index 4933912..2058002 100644
> --- a/gcc/read-md.h
> +++ b/gcc/read-md.h
> @@ -98,6 +98,9 @@ class base_rtx_reader
>    virtual ~base_rtx_reader ();
>
>    bool read_md_files (int, const char **, bool (*) (const char *));
> +  bool read_file_fragment (const char *filename,
> +                          int first_line,
> +                          int last_line);
>
>    /* A hook that handles a single .md-file directive, up to but not
>       including the closing ')'.  It takes two arguments: the file position
> @@ -159,6 +162,10 @@ class base_rtx_reader
>
>    /* A pointer to the null terminator of the md include chain.  */
>    file_name_list **m_last_dir_md_include_ptr;
> +
> +  /* If non-zero, filter the input to just this subset of lines.  */
> +  int m_first_line;
> +  int m_last_line;
>  };
>
>  /* Global singleton; constrast with rtx_reader_ptr below.  */
> diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
> index 0723585..73493ec 100644
> --- a/gcc/read-rtl-function.c
> +++ b/gcc/read-rtl-function.c
> @@ -593,23 +593,31 @@ function_reader::create_function ()
>    else
>      rtl_register_cfg_hooks ();
>
> -  /* Create cfun.  */
> -  tree fn_name = get_identifier (m_name ? m_name : "test_1");
> -  tree int_type = integer_type_node;
> -  tree return_type = int_type;
> -  tree arg_types[3] = {int_type, int_type, int_type};
> -  tree fn_type = build_function_type_array (return_type, 3, arg_types);
> -  tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
> -                                fn_type);
> -  tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
> -                            return_type);
> -  DECL_ARTIFICIAL (resdecl) = 1;
> -  DECL_IGNORED_P (resdecl) = 1;
> -  DECL_RESULT (fndecl) = resdecl;
> -  allocate_struct_function (fndecl, false);
> -  /* This sets cfun.  */
> -
> -  current_function_decl = fndecl;
> +  /* When run from selftests or "rtl1", cfun is NULL.
> +     When run from "cc1" for a C function tagged with __RTL, cfun is the
> +     tagged function.  */
> +  if (!cfun)
> +    {
> +      tree fn_name = get_identifier (m_name ? m_name : "test_1");
> +      tree int_type = integer_type_node;
> +      tree return_type = int_type;
> +      tree arg_types[3] = {int_type, int_type, int_type};
> +      tree fn_type = build_function_type_array (return_type, 3, arg_types);
> +      tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
> +                                    fn_type);
> +      tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
> +                                return_type);
> +      DECL_ARTIFICIAL (resdecl) = 1;
> +      DECL_IGNORED_P (resdecl) = 1;
> +      DECL_RESULT (fndecl) = resdecl;
> +      allocate_struct_function (fndecl, false);
> +      /* This sets cfun.  */
> +      current_function_decl = fndecl;
> +    }
> +
> +  gcc_assert (cfun);
> +  gcc_assert (current_function_decl);
> +  tree fndecl = current_function_decl;
>
>    cfun->curr_properties = (PROP_cfg | PROP_rtl);
>
> @@ -1817,6 +1825,42 @@ read_rtl_function_body (int argc, const char **argv,
>    return true;
>  }
>
> +/* Run the RTL dump parser on the range of lines between START_LOC and
> +   END_LOC (including those lines).  */
> +
> +bool
> +read_rtl_function_body_from_file_range (location_t start_loc,
> +                                       location_t end_loc)
> +{
> +  expanded_location exploc_start = expand_location (start_loc);
> +  expanded_location exploc_end = expand_location (end_loc);
> +
> +  if (exploc_start.file != exploc_end.file)
> +    {
> +      error_at (end_loc, "start/end of RTL fragment are in different files");
> +      return false;
> +    }
> +  if (exploc_start.line >= exploc_end.line)
> +    {
> +      error_at (end_loc,
> +               "start of RTL fragment must be on an earlier line than end");
> +      return false;
> +    }
> +
> +  in_rtl_frontend_p = true;
> +
> +  initialize_rtl ();
> +  init_emit ();
> +  init_varasm_status ();
> +
> +  function_reader reader (NULL);
> +  if (!reader.read_file_fragment (exploc_start.file, exploc_start.line,
> +                                 exploc_end.line - 1))
> +    return false;
> +
> +  return true;
> +}
> +
>  #if CHECKING_P
>
>  namespace selftest {
> diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
> index d26c797..c69d308 100644
> --- a/gcc/read-rtl-function.h
> +++ b/gcc/read-rtl-function.h
> @@ -34,4 +34,7 @@ extern bool read_rtl_function_body (int argc, const char **argv,
>                                     function_reader_policy *policy,
>                                     int *out_pseudo_offset);
>
> +extern bool read_rtl_function_body_from_file_range (location_t start_loc,
> +                                                   location_t end_loc);
> +
>  #endif /* GCC_READ_RTL_FUNCTION_H */
> diff --git a/gcc/testsuite/rtl.dg/rtl.exp b/gcc/testsuite/rtl.dg/rtl.exp
> index 71bebb9..6c7c7f4 100644
> --- a/gcc/testsuite/rtl.dg/rtl.exp
> +++ b/gcc/testsuite/rtl.dg/rtl.exp
> @@ -29,8 +29,10 @@ if ![info exists DEFAULT_RTLFLAGS] then {
>  # Initialize `dg'.
>  dg-init
>
> -# Gather a list of all tests.
> +# Gather a list of all tests: both .rtl tests for use with rtl1, and .c tests
> +# for use with cc1.
>  set tests [lsort [find $srcdir/$subdir *.rtl]]
> +set tests [concat $tests [lsort [find $srcdir/$subdir *.c]]]
>
>  verbose "rtl.exp tests: $tests" 1
>
> diff --git a/gcc/testsuite/rtl.dg/x86_64/different-structs.c b/gcc/testsuite/rtl.dg/x86_64/different-structs.c
> new file mode 100644
> index 0000000..d5c0bed
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/different-structs.c
> @@ -0,0 +1,101 @@
> +/* { dg-do compile { target x86_64-*-* } } */
> +
> +extern double sqrt(double x);
> +
> +struct foo
> +{
> +  double x;
> +  double y;
> +};
> +
> +struct bar
> +{
> +  double x;
> +  double y;
> +};
> +
> +double __RTL test (struct foo *f, const struct bar *b)
> +{
> +#if 0
> +  /* Result of "expand" on this C code, compiled for x86_64 with -Os.  */
> +  f->x += b->x;
> +  f->y += b->y;
> +  return sqrt (f->x * f->x + f->y * f->y);
> +#endif
> +(function "test"
> +  (insn-chain
> +    (note 1 0 5 (nil) NOTE_INSN_DELETED)
> +    (note 5 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
> +    (insn 2 5 3 2 (set (reg/v/f:DI 97 [ f ])
> +                (reg:DI 5 di [ f ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:16 -1
> +             (nil))
> +    (insn 3 2 4 2 (set (reg/v/f:DI 98 [ b ])
> +                (reg:DI 4 si [ b ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:16 -1
> +             (nil))
> +    (note 4 3 7 2 NOTE_INSN_FUNCTION_BEG)
> +    (insn 7 4 8 2 (set (reg:DF 99)
> +                (mem:DF (reg/v/f:DI 97 [ f ]) [2 f_11(D)->x+0 S8 A64])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
> +             (nil))
> +    (insn 8 7 9 2 (set (reg:DF 89 [ _3 ])
> +                (plus:DF (reg:DF 99)
> +                    (mem:DF (reg/v/f:DI 98 [ b ]) [2 b_12(D)->x+0 S8 A64]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
> +             (nil))
> +    (insn 9 8 10 2 (set (mem:DF (reg/v/f:DI 97 [ f ]) [2 f_11(D)->x+0 S8 A64])
> +                (reg:DF 89 [ _3 ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
> +             (nil))
> +    (insn 10 9 11 2 (set (reg:DF 100)
> +                (mem:DF (plus:DI (reg/v/f:DI 97 [ f ])
> +                        (const_int 8 [0x8])) [2 f_11(D)->y+0 S8 A64])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
> +             (nil))
> +    (insn 11 10 12 2 (set (reg:DF 92 [ _6 ])
> +                (plus:DF (reg:DF 100)
> +                    (mem:DF (plus:DI (reg/v/f:DI 98 [ b ])
> +                            (const_int 8 [0x8])) [2 b_12(D)->y+0 S8 A64]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
> +             (nil))
> +    (insn 12 11 13 2 (set (mem:DF (plus:DI (reg/v/f:DI 97 [ f ])
> +                        (const_int 8 [0x8])) [2 f_11(D)->y+0 S8 A64])
> +                (reg:DF 92 [ _6 ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
> +             (nil))
> +    (insn 13 12 14 2 (set (reg:DF 101)
> +                (mult:DF (reg:DF 89 [ _3 ])
> +                    (reg:DF 89 [ _3 ]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
> +             (nil))
> +    (insn 14 13 15 2 (set (reg:DF 102)
> +                (mult:DF (reg:DF 92 [ _6 ])
> +                    (reg:DF 92 [ _6 ]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
> +             (nil))
> +    (insn 15 14 16 2 (set (reg:DF 103)
> +                (plus:DF (reg:DF 101)
> +                    (reg:DF 102))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
> +             (nil))
> +    (insn 16 15 17 2 (set (reg:DF 21 xmm0)
> +                (reg:DF 103)) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
> +             (nil))
> +    (call_insn/j 17 16 18 2 (set (reg:DF 21 xmm0)
> +                (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
> +                    (const_int 0 [0]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
> +             (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>)
> +                (expr_list:REG_EH_REGION (const_int 0 [0])
> +                    (nil)))
> +            (expr_list:DF (use (reg:DF 21 xmm0))
> +                (nil)))
> +    (barrier 18 17 0)
> +  ) ;; insn-chain
> +  (cfg
> +    (bb 0
> +      (edge 0 2 (flags 0x1))
> +    ) ;; bb
> +    (bb 2
> +      (edge 2 1 (flags 0x1002))
> +    ) ;; bb
> +    (bb 1
> +    ) ;; bb
> +  ) ;; cfg
> +  (crtl
> +    (return_rtx
> +      (reg/i:DF 21 xmm0)
> +    ) ;; return_rtx
> +  ) ;; crtl
> +) ;; function "test"
> +
> +}
> diff --git a/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
> new file mode 100644
> index 0000000..11b6f24
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
> @@ -0,0 +1,23 @@
> +/* { dg-do compile { target x86_64-*-* } } */
> +
> +int __RTL test_returning_constant (void)
> +{
> +  /* C code:
> +     return 42; */
> +
> +  (function "test_returning_constant"
> +    (insn-chain
> +      (note 1 0 3 (nil) NOTE_INSN_DELETED)
> +      (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
> +      (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
> +      (insn 5 2 9 2 (set (reg:SI 87 [ <retval> ])
> +           (const_int 42 [0x2a])) test-return-const.c:3 -1
> +         (nil))
> +      (insn 9 5 10 2 (set (reg/i:SI 0 ax)
> +             (reg:SI 87 [ <retval> ])) test-return-const.c:4 -1
> +         (nil))
> +      (insn 10 9 0 2 (use (reg/i:SI 0 ax)) test-return-const.c:4 -1
> +         (nil))
> +     ) ;; insn-chain
> +   );; function
> +}
> diff --git a/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
> new file mode 100644
> index 0000000..83594b3
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile { target x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-fwprop1" } */
> +
> +int __RTL ("rtl-fwprop1") test_returning_constant (void)
> +{
> +  /* C code:
> +     return 42; */
> +  (function "test"
> +    (insn-chain
> +      (note 3 0 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
> +      (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
> +      (insn 5 2 9 2 (set (reg:SI 87 [ <retval> ])
> +        (const_int 42 [0x2a])) test-return-const.c:3 82 {*movsi_internal}
> +        (nil))
> +      (insn 9 5 10 2 (set (reg/i:SI 0 ax)
> +       (const_int 42 [0x2a])) test-return-const.c:4 82 {*movsi_internal}
> +        (expr_list:REG_DEAD (reg:SI 87 [ <retval> ])
> +        (nil)))
> +      (insn 10 9 0 2 (use (reg/i:SI 0 ax)) test-return-const.c:4 -1
> +       (nil))
> +    ) ;; insn-chain
> +  ) ;; function
> +}
> +
> +/* Verify that insn 5 is eliminated.  */
> +/* { dg-final { scan-rtl-dump "deferring deletion of insn with uid = 5" "fwprop1" } } */
> +/* { dg-final { scan-rtl-dump "Deleted 1 trivially dead insns" "fwprop1" } } */
> diff --git a/gcc/testsuite/rtl.dg/x86_64/test-rtl.c b/gcc/testsuite/rtl.dg/x86_64/test-rtl.c
> new file mode 100644
> index 0000000..0ffeab7
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/test-rtl.c
> @@ -0,0 +1,95 @@
> +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
> +
> +/* Test of embedding RTL dump in a C function, tagged with "__RTL".
> +
> +   This is a dump of test.c from immediately after "expand", for x86_64.  */
> +
> +int __RTL test_1 (int i, int j, int k)
> +{
> +  /*
> +    if (i < j)
> +      return k + 4;
> +    else
> +      return -k;
> +  */
> +  (function "test_1"
> +   (insn-chain
> +  (note 1 0 6 (nil) NOTE_INSN_DELETED)
> +(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
> +(insn 2 6 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 ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
> +     (nil))
> +(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
> +                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
> +        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
> +     (nil))
> +(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
> +                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
> +        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
> +     (nil))
> +(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
> +(insn 8 5 9 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])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
> +     (nil))
> +(insn 9 8 10 2 (set (reg:CCGC 17 flags)
> +        (compare:CCGC (reg:SI 89)
> +            (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
> +                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
> +     (nil))
> +(jump_insn 10 9 11 2 (set (pc)
> +        (if_then_else (ge (reg:CCGC 17 flags)
> +                (const_int 0 [0]))
> +            (label_ref 16)
> +            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
> +     (nil)
> + -> 16)
> +(note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
> +(insn 12 11 13 4 (set (reg:SI 90)
> +        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
> +                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
> +     (nil))
> +(insn 13 12 14 4 (parallel [
> +            (set (reg:SI 87 [ _1 ])
> +                (plus:SI (reg:SI 90)
> +                    (const_int 4 [0x4])))
> +            (clobber (reg:CC 17 flags))
> +        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
> +     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
> +                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
> +            (const_int 4 [0x4]))
> +        (nil)))
> +(jump_insn 14 13 15 4 (set (pc)
> +        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
> +     (nil)
> + -> 20)
> +(barrier 15 14 16)
> +(code_label 16 15 17 5 2 (nil) [1 uses])
> +(note 17 16 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
> +(insn 18 17 19 5 (set (reg:SI 91)
> +        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
> +                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
> +     (nil))
> +(insn 19 18 20 5 (parallel [
> +            (set (reg:SI 87 [ _1 ])
> +                (neg:SI (reg:SI 91)))
> +            (clobber (reg:CC 17 flags))
> +        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
> +     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
> +                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
> +        (nil)))
> +(code_label 20 19 21 6 3 (nil) [1 uses])
> +(note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
> +(insn 22 21 26 6 (set (reg:SI 88 [ <retval> ])
> +        (reg:SI 87 [ _1 ])) -1
> +     (nil))
> +(insn 26 22 27 6 (set (reg/i:SI 0 ax)
> +        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
> +     (nil))
> +(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
> +     (nil))
> +
> +    ) ;; insn-chain
> +   ) ;; function
> +}
> diff --git a/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c b/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
> new file mode 100644
> index 0000000..8536bf4
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
> @@ -0,0 +1,40 @@
> +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
> +
> +int __RTL times_two (int i)
> +{
> +  /* C function:
> +     return i * 2;  */
> +  (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 ])) times-two.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])) times-two.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))
> +        ]) times-two.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 ])) times-two.c:3 -1
> +     (nil))
> +  (insn 14 10 15 2 (set (reg/i:SI 0 ax)
> +        (reg:SI 88 [ <retval> ])) times-two.c:4 -1
> +     (nil))
> +  (insn 15 14 0 2 (use (reg/i:SI 0 ax)) times-two.c:4 -1
> +     (nil))
> +    ) ;; insn-chain
> +  ) ;; function
> +}
> diff --git a/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c b/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
> new file mode 100644
> index 0000000..b4d20a7
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
> @@ -0,0 +1,57 @@
> +/* { dg-do compile { target x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-dfinit" } */
> +
> +int __RTL ("rtl-dfinit") times_two (int i)
> +{
> +  /* C function:
> +     return i * 2;  */
> + (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 20 frame)
> +                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
> +        (reg:SI 5 di [ i ])) times-two.c:2 82 {*movsi_internal}
> +     (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 20 frame)
> +                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) times-two.c:3 82 {*movsi_internal}
> +     (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))
> +        ]) times-two.c:3 529 {*ashlsi3_1}
> +     (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
> +                    (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 ])) times-two.c:3 82 {*movsi_internal}
> +     (nil))
> +   (insn 14 10 15 2 (set (reg/i:SI 0 ax)
> +        (reg:SI 88 [ <retval> ])) times-two.c:4 82 {*movsi_internal}
> +     (nil))
> +   (insn 15 14 0 2 (use (reg/i:SI 0 ax)) times-two.c:4 -1
> +     (nil))
> +   ) ;; insn-chain
> +
> +   (crtl
> +     (return_rtx
> +       (reg/i:SI 0 ax)
> +     ) ;; return_rtx
> +   ) ;; crtl
> +  ) ;; function
> +}
> +
> +/* Verify that the dataflow information matches what cc1 would have
> +   generated.  In particular, in earlier versions of the RTL
> +   frontend, the exit block use of reg 0 (ax) wasn't picked up
> +   on, due to not setting up crtl->return_rtx based on
> +   DECL_RESULT (fndecl).  */
> +
> +/* { dg-final { scan-rtl-dump ";;  exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
> +
> +/* { dg-final { scan-rtl-dump ";;  regs ever live.*0 .ax. 5 .di. 17 .flags." "dfinit" } } */
> --
> 1.8.5.3
>

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

* Re: [PATCH] Add "__RTL" to cc1 (v2)
  2016-10-13 13:49       ` Richard Biener
@ 2016-10-13 13:52         ` Bernd Schmidt
  2016-10-14  9:33           ` Richard Biener
  2016-10-14 19:23         ` David Malcolm
  1 sibling, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-13 13:52 UTC (permalink / raw)
  To: Richard Biener, David Malcolm; +Cc: Joseph Myers, GCC Patches

On 10/13/2016 03:49 PM, Richard Biener wrote:
> Does it really run a single pass only?  Thus you can't do a { dg-do run } test
> with __RTL?

I think that's really not the intended use-case. To my mind this is for 
unit-testing: ensuring that a given rtl pass performs the expected 
transformation on an input.


Bernd

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

* Re: [PATCH] Tweaks to print_rtx_function
  2016-10-13 10:24                   ` Bernd Schmidt
@ 2016-10-13 14:08                     ` David Malcolm
  2016-10-13 14:18                       ` Bernd Schmidt
  0 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-13 14:08 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches

On Thu, 2016-10-13 at 12:24 +0200, Bernd Schmidt wrote:
> On 10/12/2016 11:04 PM, David Malcolm wrote:
> > 
> > This patch implements:
> > * the renumbering of non-virtual pseudos, using
> >   LAST_VIRTUAL_REGISTER + 1 as a base.
> > * omitting the edge "(flags)" directive if there aren't any
> > 
> > Bootstrap & regrtest in progress.
> > 
> > OK for trunk if they pass?

(they did)

> I tend to think probably yes. Let's say ok if I don't object by
> tomorrow 
> :) I'm still wondering whether we want to use some sort of prefix
> like 
> $p or %p which is distinct from any hard register name for clarity.

I'll attempt to sum up the discussion on this so far...

We're already printing names for hard regs and for virtual regs, so
it's non-virtual pseudos that need figuring out.


Consider regno == 90 for target x86_64, where LAST_VIRTUAL_REGISTER is
86 and hence this is a non-virtual pseudo.  The first non-virtual
pseudo has regno 87.

Currently this is printed in non-compact form as:

  (reg:SI 90)

Our goals for printing it in "compact" form (and hence parsed by the
RTL frontend) are (in no particular order):

* readability for humans
* lack of ambiguity for parsers
* "hackability" for humans editing the file
* future-proof against changes to the machine description
* make it reasonably target-independent

I thought it might be useful to brainstorm [1] some ideas on this, so here are various possible ways it could be printed for this use-case:

* Offset by LAST_VIRTUAL_REGISTER + 1 (as in the patch), and printed
just as a number, giving:

  (reg:SI 3) 

* Prefixed by a "sigil" character:

  (reg:SI $3) 
  (reg:SI %3) 
  (reg:SI #3) 
  (reg:SI +3)
  (reg:SI @3)
 
(reg:SI &3)
  (reg:SI ?3)
  (reg:SI P3)

* Prefixed so it looks like a register name:

  (reg:SI pseudo-3)
  (reg:SI pseudo_3)
  (reg:SI pseudo+3)


* Other syntax ideas:

  (reg:SI (3))

  (reg:SI {3})

  (reg:SI (87+3))
  (reg:SI (LAST_VIRTUAL_REGISTER + 4))

Looking at print_rtx_operand_code_r there are also things like ORIGINAL_REGNO, REG_EXPR and REG_OFFSET which get printed after the main regno, e.g.:

  (reg:SI 1 [ <retval> ])

My thought was to use whatever we come up with for REGNO for ORIGINAL_REGNO (after the "orig:").	

Hope this is constructive
Dave

[1] i.e. this is my list before applying any "is this idea a good one" filtering/self-censorship...


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

* Re: [PATCH] Tweaks to print_rtx_function
  2016-10-13 14:08                     ` David Malcolm
@ 2016-10-13 14:18                       ` Bernd Schmidt
  2016-10-14 19:41                         ` [PATCH] (v2) " David Malcolm
  0 siblings, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-13 14:18 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/13/2016 04:08 PM, David Malcolm wrote:
> I thought it might be useful to brainstorm [1] some ideas on this,
> so  here are various possible ways it could be printed for this use-case:
>
> * Offset by LAST_VIRTUAL_REGISTER + 1 (as in the patch), and printed
> just as a number, giving:
>
>   (reg:SI 3)

Unambiguous in the compact format, nice low register numbers, but some 
potential for confusion with hard regs based on what people are used to.

> * Prefixed by a "sigil" character:

 >   (reg:SI %3)

Avoids the confusion issue and shouldn't overlap with hard register 
names. I think this is the one I prefer, followed by plain (reg:SI 3).

>   (reg:SI P3)

Can't use this, as there are machines with P3 registers.

> * Prefixed so it looks like a register name:
>
>   (reg:SI pseudo-3)
>   (reg:SI pseudo_3)
>   (reg:SI pseudo+3)

Not too different from just a "%" prefix and probably too verbose.

> Looking at print_rtx_operand_code_r there are also things like
> ORIGINAL_REGNO, REG_EXPR and REG_OFFSET which get printed after the
> main regno, e.g.: >

>   (reg:SI 1 [ <retval> ])

That's the REG_EXPR here presumably? The interesting part comes when 
parsing this.


Bernd

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

* [PATCH] Omit INSN_LOCATION from compact dumps
  2016-10-13 10:21                   ` Bernd Schmidt
@ 2016-10-13 15:22                     ` David Malcolm
  2016-10-13 15:50                       ` Bernd Schmidt
  0 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-13 15:22 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm

On Thu, 2016-10-13 at 12:21 +0200, Bernd Schmidt wrote:
> On 10/12/2016 10:37 PM, David Malcolm wrote:
> > It didn't pass, due to this change:
> > 
> >      (print_rtx_operand_code_i): When printing source locations,
> > wrap
> >      xloc.file in quotes. [...snip...]
> [...]
> > The following is a revised version of the patch which updates this
> > test case.
> 
> Also ok.

(committed to trunk as r241120)

> This reminds me, wrapping the filename in quotes was a side
> issue - what I was really hoping for was to have testcases without
> this
> visual clutter unless they wanted to explicitly test functionality
> related to it.

The following patch omits the INSN_LOCATION in compact mode.

Currently bootstrapping&regrtesting.

OK for trunk if it passes?

Alternatively, it seems that we might want an additional flag for
this.  If so, maybe it's time to introduce a "class rtx_writer" or
similar to hold the global state relating to dumping, and rewrite
the dumping in those terms?

gcc/ChangeLog:
	* print-rtl-function.c (print_rtx_function): Update comment for
	omission of INSN_LOCATIONs in compact mode.
	* print-rtl.c (print_rtx_operand_code_i): Omit INSN_LOCATIONs in
	compact mode.
---
 gcc/print-rtl-function.c | 13 +++++++------
 gcc/print-rtl.c          |  5 +++--
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/gcc/print-rtl-function.c b/gcc/print-rtl-function.c
index 90a0ff7..87a6458 100644
--- a/gcc/print-rtl-function.c
+++ b/gcc/print-rtl-function.c
@@ -133,6 +133,7 @@ can_have_basic_block_p (const rtx_insn *insn)
    - INSN_CODEs are omitted,
    - register numbers are omitted for hard and virtual regs
    - insn names are prefixed with "c" (e.g. "cinsn", "cnote", etc)
+   - INSN_LOCATIONs are omitted.
 
    Example output (with COMPACT==true):
 
@@ -144,30 +145,30 @@ can_have_basic_block_p (const rtx_insn *insn)
 	 (cnote [bb 2] NOTE_INSN_BASIC_BLOCK)
 	 (cinsn (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
 			       (const_int -4)) [1 i+0 S4 A32])
-		       (reg:SI di [ i ])) "t.c":2
+		       (reg:SI di [ i ]))
 		   (nil))
 	 (cnote NOTE_INSN_FUNCTION_BEG)
 	 (cinsn (set (reg:SI 89)
 		       (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
-			       (const_int -4)) [1 i+0 S4 A32])) "t.c":3
+			       (const_int -4)) [1 i+0 S4 A32]))
 		   (nil))
 	 (cinsn (parallel [
 			   (set (reg:SI 87 [ _2 ])
 			       (ashift:SI (reg:SI 89)
 				   (const_int 1)))
 			   (clobber (reg:CC flags))
-		       ]) "t.c":3
+		       ])
 		   (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
 				   (const_int -4)) [1 i+0 S4 A32])
 			   (const_int 1))
 		       (nil)))
 	 (cinsn (set (reg:SI 88 [ <retval> ])
-		       (reg:SI 87 [ _2 ])) "t.c":3
+		       (reg:SI 87 [ _2 ]))
 		   (nil))
 	 (cinsn (set (reg/i:SI ax)
-		       (reg:SI 88 [ <retval> ])) "t.c":4
+		       (reg:SI 88 [ <retval> ]))
 		   (nil))
-	 (cinsn (use (reg/i:SI ax)) "t.c":4
+	 (cinsn (use (reg/i:SI ax))
 		   (nil))
 	 (edge-to exit (flags "FALLTHRU"))
        ) ;; block 2
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index f114cb4..2bf7a13 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -288,8 +288,9 @@ print_rtx_operand_code_i (const_rtx in_rtx, int idx)
 
       /*  Pretty-print insn locations.  Ignore scoping as it is mostly
 	  redundant with line number information and do not print anything
-	  when there is no location information available.  */
-      if (INSN_HAS_LOCATION (in_insn))
+	  when there is no location information available.
+	  Don't print locations when in compact mode.  */
+      if (INSN_HAS_LOCATION (in_insn) && !flag_compact)
 	{
 	  expanded_location xloc = insn_location (in_insn);
 	  fprintf (outfile, " \"%s\":%i", xloc.file, xloc.line);
-- 
1.8.5.3

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

* Re: [PATCH] Omit INSN_LOCATION from compact dumps
  2016-10-13 15:22                     ` [PATCH] Omit INSN_LOCATION from compact dumps David Malcolm
@ 2016-10-13 15:50                       ` Bernd Schmidt
  0 siblings, 0 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-13 15:50 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/13/2016 05:52 PM, David Malcolm wrote:

> Alternatively, it seems that we might want an additional flag for
> this.

Probably - I imagine most testcases won't care (it's obviously easier to 
read without locations) but some will. The writing side is maybe less 
interesting than the reading side, making sure we parse either variant 
correctly.

> If so, maybe it's time to introduce a "class rtx_writer" or
> similar to hold the global state relating to dumping, and rewrite
> the dumping in those terms?

Depends how invasive that's going to be. I have no clear picture of it.


Bernd

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

* Re: [PATCH] Add "__RTL" to cc1 (v2)
  2016-10-13 13:52         ` Bernd Schmidt
@ 2016-10-14  9:33           ` Richard Biener
  2016-10-14  9:48             ` Bernd Schmidt
  2016-10-14 19:25             ` David Malcolm
  0 siblings, 2 replies; 96+ messages in thread
From: Richard Biener @ 2016-10-14  9:33 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: David Malcolm, Joseph Myers, GCC Patches

On Thu, Oct 13, 2016 at 3:51 PM, Bernd Schmidt <bschmidt@redhat.com> wrote:
> On 10/13/2016 03:49 PM, Richard Biener wrote:
>>
>> Does it really run a single pass only?  Thus you can't do a { dg-do run }
>> test
>> with __RTL?
>
>
> I think that's really not the intended use-case. To my mind this is for
> unit-testing: ensuring that a given rtl pass performs the expected
> transformation on an input.

Ok, so at least for the GIMPLE FE side I thought it's useful to allow
a correctness verification with something simpler than pattern matching
on the pass output.  By means of doing runtime verification of an expected
result (this necessarily includes running followup passes as we have to
generate code).  I don't see why this shouldn't apply to __RTL -- it might
be more difficult to get __RTL testcases to the point where they emit
assembly of course.

OTOH the question then still is what's the default behavior if you do _not_
specify a "single pass to run".

Richard.

>
> Bernd

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

* Re: [PATCH] Add "__RTL" to cc1 (v2)
  2016-10-14  9:33           ` Richard Biener
@ 2016-10-14  9:48             ` Bernd Schmidt
  2016-10-14  9:50               ` Richard Biener
  2016-10-14 19:25             ` David Malcolm
  1 sibling, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-14  9:48 UTC (permalink / raw)
  To: Richard Biener; +Cc: David Malcolm, Joseph Myers, GCC Patches

On 10/14/2016 11:33 AM, Richard Biener wrote:

> Ok, so at least for the GIMPLE FE side I thought it's useful to allow
> a correctness verification with something simpler than pattern matching
> on the pass output.  By means of doing runtime verification of an expected
> result (this necessarily includes running followup passes as we have to
> generate code).  I don't see why this shouldn't apply to __RTL -- it might
> be more difficult to get __RTL testcases to the point where they emit
> assembly of course.

Also, if this ends up with a lot of testcases, I still think it would be 
best to have these use a special rtl-test port so that the tests don't 
become a maintenance burden for real ports, and so that we can construct 
the tests any way we like.
Such a port might not even be able to produce executable code (unless 
you also want to write a sim).


Bernd

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

* Re: [PATCH] Add "__RTL" to cc1 (v2)
  2016-10-14  9:48             ` Bernd Schmidt
@ 2016-10-14  9:50               ` Richard Biener
  0 siblings, 0 replies; 96+ messages in thread
From: Richard Biener @ 2016-10-14  9:50 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: David Malcolm, Joseph Myers, GCC Patches

On Fri, Oct 14, 2016 at 11:48 AM, Bernd Schmidt <bschmidt@redhat.com> wrote:
> On 10/14/2016 11:33 AM, Richard Biener wrote:
>
>> Ok, so at least for the GIMPLE FE side I thought it's useful to allow
>> a correctness verification with something simpler than pattern matching
>> on the pass output.  By means of doing runtime verification of an expected
>> result (this necessarily includes running followup passes as we have to
>> generate code).  I don't see why this shouldn't apply to __RTL -- it might
>> be more difficult to get __RTL testcases to the point where they emit
>> assembly of course.
>
>
> Also, if this ends up with a lot of testcases, I still think it would be
> best to have these use a special rtl-test port so that the tests don't
> become a maintenance burden for real ports, and so that we can construct the
> tests any way we like.
> Such a port might not even be able to produce executable code (unless you
> also want to write a sim).

Sure - I don't say running only a single pass doesn't make sense in some cases.
It just adds a less fragile way of testing for correctness.

Richard.

>
> Bernd

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

* [PATCH] read-md.c: Move various state to within class rtx_reader
  2016-10-12 21:57       ` Richard Sandiford
@ 2016-10-14 17:45         ` David Malcolm
  2016-10-17 11:05           ` Bernd Schmidt
  2016-10-17 11:37           ` Richard Sandiford
  0 siblings, 2 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-14 17:45 UTC (permalink / raw)
  To: Richard Sandiford, Bernd Schmidt, gcc-patches; +Cc: David Malcolm

On Wed, 2016-10-12 at 22:57 +0100, Richard Sandiford wrote:
> Sorry, haven't had time to read the full series yet, but:
> 
> David Malcolm <dmalcolm@redhat.com> writes:
> > On Wed, 2016-10-05 at 17:51 +0200, Bernd Schmidt wrote:
> > > On 10/05/2016 06:14 PM, David Malcolm wrote:
> > > > The selftests for the RTL frontend require supporting multiple
> > > > reader instances being alive one after another in-process, so
> > > > this lack of cleanup would become a leak.
> > > 
> > > > +  /* Initialize global data.  */
> > > > +  obstack_init (&string_obstack);
> > > > +  ptr_locs = htab_create (161, leading_ptr_hash,
> > > > leading_ptr_eq_p,
> > > > 0);
> > > > +  obstack_init (&ptr_loc_obstack);
> > > > +  joined_conditions = htab_create (161, leading_ptr_hash,
> > > > leading_ptr_eq_p, 0);
> > > > +  obstack_init (&joined_conditions_obstack);
> > > > +  md_constants = htab_create (31, leading_string_hash,
> > > > +			      leading_string_eq_p, (htab_del)
> > > > 0);
> > > > +  enum_types = htab_create (31, leading_string_hash,
> > > > +			    leading_string_eq_p, (htab_del)
> > > > 0);
> > > > +
> > > > +  /* Unlock the stdio streams.  */
> > > > +  unlock_std_streams ();
> > > 
> > > Hmm, but these are global statics. Shouldn't they first be moved
> > > to
> > > become class members?
> > 
> > [CCing Richard Sandiford]
> > 
> > I tried to move these into class rtx_reader, but doing so rapidly
> > became quite invasive, with many of functions in the gen* tools
> > becoming methods.
> 
> Is that just to avoid introducing explicit references to the global
> rtx_reader object in the gen* tools?  If so, then TBH adding those
> references sound better to me than tying generator-specific functions
> to the rtx reader (not least because most of them do more than just
> read rtl).
> 
> > Arguably that would be a good thing, but there are a couple of
> > issues:
> > 
> > (a) some of these functions take "vec" arguments; moving them from
> > static functions to being class methods requires that vec.h has
> > been
> > included when the relevant class decl is parsed.
> 
> I don't think including vec.h more often should be a blocker though.
> :-)
> 
> > (b) rtx_reader turns into a bug dumping ground of methods, for the
> > union of all of the various gen* tools.
> > 
> > One way to alleviate these issues would be to do the split of
> > rtx_reader into base_rtx_reader vs rtx_reader from patch 9 of the
> > kit:
> >   https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00273.html
> > and perhaps to split out part of read-md.h into a new read-rtl.h.
> > 
> > Before I reorganize the patches, does this approach sound
> > reasonable?
> > 
> > Alternatively, a less invasive approach is to have an accessor for
> > these fields, so that things using them can get at them via the
> > rtx_reader_ptr singleton e.g.:
> > 
> > void
> > grow_string_obstack (char ch)
> > {
> >    obstack_1grow (rtx_reader_ptr->get_string_obstack (), ch);
> > }
> > 
> > and similar.
> 
> I think it's OK for the generators to refer rtx_reader_ptr directly.
> Obviously that makes the patches more invasive, but hopefully the
> extra changes are mechanical.
> 
> Thanks,
> Richard

Thanks.

Here's an updated version of the patch.

As before:

Various global data items relating to reading .md files are
currently initialized in rtx_reader::read_md_files, and are
not cleaned up.

The selftests for the RTL frontend require supporting multiple
reader instances being alive one after another in-process, so
this lack of cleanup would become a leak.

What's new:

In this version of the patch, I've moved the global variables to
be fields of class rtx_reader, moving their setup to the constructor.
The patch adds matching cleanups to the destructor, along with a
cleanup of m_base_dir.

Doing so requires updating the various users of these fields.
Where it seemed appropriate, I made the functions be methods
of rtx_reader.  In other cases, I updated them to access the fields
via rtx_reader_ptr.

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.

Comparing md5sums of BUILD/gcc/insn-*.[hc] before/after shows them to be
unchanged by the patch.

OK for trunk?

gcc/ChangeLog:
	* genattrtab.c (gen_attr): Use rtx_reader_ptr for lookup_enum_type
	call.
	* genconstants.c: Include "statistics.h" and "vec.h".
	(main): Update for conversion of traverse_enum_types to a method.
	* genenums.c: Include "statistics.h" and "vec.h".
	(main): Update for conversion of traverse_enum_types to a method.
	* genmddeps.c: Include "statistics.h" and "vec.h".
	* gensupport.c (gen_mnemonic_setattr): Update for move of
	string_obstack to a field of rtx_reader.
	(mnemonic_htab_callback): Likewise.
	(gen_mnemonic_attr): Likewise.
	* read-md.c: Include "statistics.h" and "vec.h".
	(string_obstack): Convert this global to field "m_string_obstack"
	of class rtx_reader.
	(ptr_locs): Likewise, as "m_ptr_locs".
	(ptr_loc_obstack): Likewise, as "m_ptr_loc_obstack".
	(joined_conditions): Likewise, as "m_joined_conditions".
	(joined_conditions_obstack): Likewise, as "m_joined_conditions_obstack".
	(md_constants): Likewise, as "m_md_constants".
	(enum_types): Likewise, as "m_enum_types".
	(set_md_ptr_loc): Convert from function to...
	(rtx_reader::set_md_ptr_loc): ...this method.
	(get_md_ptr_loc): Convert from function to...
	(rtx_reader::get_md_ptr_loc): ...this method.
	(copy_md_ptr_loc): Use rtx_reader_ptr when calling methods.
	(fprint_md_ptr_loc): Likewise.
	(join_c_conditions): Convert from function to...
	(rtx_reader::join_c_conditions): ...this method.
	(join_c_conditions): Reinstate, with a new function calling the
	above method.
	(fprint_c_condition): Convert from function to...
	(rtx_reader::fprint_c_condition): ...this method.
	(fprint_c_condition): Reinstate, with a new function calling the
	above method.
	(read_name): Convert from function to...
	(rtx_reader::read_name): ...this method.
	(read_escape): Convert from function to...
	(rtx_reader::read_escape): ...this method.
	(read_quoted_string): Convert from function to...
	(rtx_reader::read_quoted_string): ...this method.
	(read_braced_string): Convert from function to...
	(rtx_reader::read_braced_string): ...this method.
	(read_string): Convert from function to...
	(rtx_reader::read_string): ...this method.
	(read_skip_construct): Convert from function to...
	(rtx_reader::read_skip_construct): ...this method.
	(handle_constants): Convert from function to...
	(rtx_reader::handle_constants): ...this method.
	(traverse_md_constants): Use rtx_reader_ptr when calling methods.
	(handle_enum): Convert from function to...
	(rtx_reader::handle_enum): ...this method.
	(lookup_enum_type): Convert from function to...
	(rtx_reader::lookup_enum_type): ...this method.
	(traverse_enum_types): Convert from function to...
	(rtx_reader::traverse_enum_types): ...this method.
	(rtx_reader::rtx_reader): Move initializations
	of various former global data from rtx_reader::read_md_files to
	here, as fields, along with the call to unlock_std_streams.
	(rtx_reader::~rtx_reader): Clean up m_base_dir, and clean up
	the new fields.
	(rtx_reader::read_md_files): Move initializations of various
	global data from here to the ctor.
	* read-md.h (read_name): Convert global decl to...
	(rtx_reader::read_name): ...this new method decl.
	(rtx_reader::read_escape): New method decl.
	(read_quoted_string): Convert global decl to...
	(rtx_reader::read_quoted_string): ...this new method decl.
	(rtx_reader::read_braced_string): New method decl.
	(read_string): Convert global decl to...
	(rtx_reader::read_string): ...this new method decl.
	(rtx_reader::read_skip_construct): New method decl.
	(rtx_reader::set_md_ptr_loc): New method decl.
	(rtx_reader::get_md_ptr_loc): New method decl.
	(rtx_reader::lookup_enum_type): New method decl.
	(rtx_reader::traverse_enum_types): New method decl.
	(rtx_reader::handle_constants): New method decl.
	(rtx_reader::handle_enum): New method decl.
	(rtx_reader::join_c_conditions): New method decl.
	(rtx_reader::fprint_c_condition): New method decl.
	(rtx_reader::apply_iterator_to_string): New method decl.
	(rtx_reader::copy_rtx_for_iterators): New method decl.
	(rtx_reader::read_conditions): New method decl.
	(rtx_reader::record_potential_iterator_use): New method decl.
	(rtx_reader::read_mapping): New method decl.
	(rtx_reader::read_rtx): New method decl.
	(rtx_reader::read_rtx_code): New method decl.
	(rtx_reader::read_rtx_operand): New method decl.
	(rtx_reader::read_nested_rtx): New method decl.
	(rtx_reader::read_rtx_variadic): New method decl.
	(rtx_reader::get_string_obstack): New method.
	(rtx_reader::get_md_constants): New method.
	(string_obstack): Convert global decl to...
	(rtx_reader::m_string_obstack): ...this new field.
	(rtx_reader::m_ptr_locs): New field.
	(rtx_reader::m_ptr_loc_obstack): New field.
	(rtx_reader::m_joined_conditions): New field.
	(rtx_reader::m_joined_conditions_obstack): New field.
	(rtx_reader::m_md_constants): New field.
	(rtx_reader::m_enum_types): New field.
	(fprint_md_ptr_loc): Delete global decl.
	* read-rtl.c (apply_iterator_to_string): Convert to...
	(rtx_reader::apply_iterator_to_string): ...this method.
	(copy_rtx_for_iterators): Convert to...
	(rtx_reader::copy_rtx_for_iterators): ...this method.
	(apply_iterators): Use rtx_reader_ptr for copy_rtx_for_iterators
	call.
	(read_conditions): Convert to...
	(rtx_reader::read_conditions): ...this method.
	(record_potential_iterator_use): Convert to...
	(rtx_reader::record_potential_iterator_use): ...this method.
	(read_mapping): Convert to...
	(rtx_reader::read_mapping): ...this method.
	(read_subst_mapping): Use rtx_reader_ptr for read_string call.
	(read_rtx): Convert to...
	(rtx_reader::read_rtx): ...this method.
	(read_rtx_code): Convert to...
	(rtx_reader::read_rtx_code): ...this method.
	(read_rtx_operand): Convert from function to...
	(rtx_reader::read_rtx_operand): ...this method.  Update for move
	of string_obstack to a field.
	(read_nested_rtx): Convert from function to..
	(rtx_reader::read_nested_rtx): ...this method.
	(read_rtx_variadic): Convert from function to..
	(rtx_reader::read_rtx_variadic): ...this method.
---
 gcc/genattrtab.c   |   2 +-
 gcc/genconstants.c |   4 +-
 gcc/genenums.c     |   4 +-
 gcc/genmddeps.c    |   2 +
 gcc/gensupport.c   |  28 ++++---
 gcc/read-md.c      | 209 ++++++++++++++++++++++++++++-------------------------
 gcc/read-md.h      |  66 +++++++++++++++--
 gcc/read-rtl.c     |  72 +++++++++---------
 8 files changed, 230 insertions(+), 157 deletions(-)

diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c
index dbcdcfc..5a844f4 100644
--- a/gcc/genattrtab.c
+++ b/gcc/genattrtab.c
@@ -3157,7 +3157,7 @@ gen_attr (md_rtx_info *info)
   if (GET_CODE (def) == DEFINE_ENUM_ATTR)
     {
       attr->enum_name = XSTR (def, 1);
-      et = lookup_enum_type (XSTR (def, 1));
+      et = rtx_reader_ptr->lookup_enum_type (XSTR (def, 1));
       if (!et || !et->md_p)
 	error_at (info->loc, "No define_enum called `%s' defined",
 		  attr->name);
diff --git a/gcc/genconstants.c b/gcc/genconstants.c
index e8be5b6..a018889 100644
--- a/gcc/genconstants.c
+++ b/gcc/genconstants.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "errors.h"
+#include "statistics.h"
+#include "vec.h"
 #include "read-md.h"
 
 /* Called via traverse_md_constants; emit a #define for
@@ -92,7 +94,7 @@ main (int argc, const char **argv)
   puts ("#define GCC_INSN_CONSTANTS_H\n");
 
   traverse_md_constants (print_md_constant, 0);
-  traverse_enum_types (print_enum_type, 0);
+  reader.traverse_enum_types (print_enum_type, 0);
 
   puts ("\n#endif /* GCC_INSN_CONSTANTS_H */");
 
diff --git a/gcc/genenums.c b/gcc/genenums.c
index 8af8d9a..2dc98ce 100644
--- a/gcc/genenums.c
+++ b/gcc/genenums.c
@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "errors.h"
+#include "statistics.h"
+#include "vec.h"
 #include "read-md.h"
 
 /* Called via traverse_enum_types.  Emit an enum definition for
@@ -59,7 +61,7 @@ main (int argc, const char **argv)
   puts ("#include \"system.h\"\n");
   puts ("#include \"insn-constants.h\"\n");
 
-  traverse_enum_types (print_enum_type, 0);
+  reader.traverse_enum_types (print_enum_type, 0);
 
   if (ferror (stdout) || fflush (stdout) || fclose (stdout))
     return FATAL_EXIT_CODE;
diff --git a/gcc/genmddeps.c b/gcc/genmddeps.c
index e3d229d..f97020f 100644
--- a/gcc/genmddeps.c
+++ b/gcc/genmddeps.c
@@ -19,6 +19,8 @@
 #include "system.h"
 #include "coretypes.h"
 #include "errors.h"
+#include "statistics.h"
+#include "vec.h"
 #include "read-md.h"
 
 
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index cb74aea..6ef6c11 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2299,6 +2299,7 @@ gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn)
   rtx set_attr;
   char *attr_name;
   rtvec new_vec;
+  struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack ();
 
   template_code = XTMPL (insn, 3);
 
@@ -2324,13 +2325,13 @@ gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn)
 	  sp = ep + 1;
 
       if (i > 0)
-	obstack_1grow (&string_obstack, ',');
+	obstack_1grow (string_obstack, ',');
 
       while (cp < sp && ((*cp >= '0' && *cp <= '9')
 			 || (*cp >= 'a' && *cp <= 'z')))
 
 	{
-	  obstack_1grow (&string_obstack, *cp);
+	  obstack_1grow (string_obstack, *cp);
 	  cp++;
 	  size++;
 	}
@@ -2341,7 +2342,7 @@ gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn)
 	    {
 	      /* Don't set a value if there are more than one
 		 instruction in the string.  */
-	      obstack_blank_fast (&string_obstack, -size);
+	      obstack_blank_fast (string_obstack, -size);
 	      size = 0;
 
 	      cp = sp;
@@ -2350,22 +2351,22 @@ gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn)
 	  cp++;
 	}
       if (size == 0)
-	obstack_1grow (&string_obstack, '*');
+	obstack_1grow (string_obstack, '*');
       else
 	add_mnemonic_string (mnemonic_htab,
-			     (char *) obstack_next_free (&string_obstack) - size,
+			     (char *) obstack_next_free (string_obstack) - size,
 			     size);
       i++;
     }
 
   /* An insn definition might emit an empty string.  */
-  if (obstack_object_size (&string_obstack) == 0)
+  if (obstack_object_size (string_obstack) == 0)
     return;
 
-  obstack_1grow (&string_obstack, '\0');
+  obstack_1grow (string_obstack, '\0');
 
   set_attr = rtx_alloc (SET_ATTR);
-  XSTR (set_attr, 1) = XOBFINISH (&string_obstack, char *);
+  XSTR (set_attr, 1) = XOBFINISH (string_obstack, char *);
   attr_name = XNEWVAR (char, strlen (MNEMONIC_ATTR_NAME) + 1);
   strcpy (attr_name, MNEMONIC_ATTR_NAME);
   XSTR (set_attr, 0) = attr_name;
@@ -2388,8 +2389,10 @@ gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn)
 static int
 mnemonic_htab_callback (void **slot, void *info ATTRIBUTE_UNUSED)
 {
-  obstack_grow (&string_obstack, (char*)*slot, strlen ((char*)*slot));
-  obstack_1grow (&string_obstack, ',');
+  struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack ();
+
+  obstack_grow (string_obstack, (char*)*slot, strlen ((char*)*slot));
+  obstack_1grow (string_obstack, ',');
   return 1;
 }
 
@@ -2407,6 +2410,7 @@ gen_mnemonic_attr (void)
   htab_t mnemonic_htab;
   const char *str, *p;
   int i;
+  struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack ();
 
   if (have_error)
     return;
@@ -2470,8 +2474,8 @@ gen_mnemonic_attr (void)
   htab_traverse (mnemonic_htab, mnemonic_htab_callback, NULL);
 
   /* Replace the last ',' with the zero end character.  */
-  *((char *)obstack_next_free (&string_obstack) - 1) = '\0';
-  XSTR (mnemonic_attr, 1) = XOBFINISH (&string_obstack, char *);
+  *((char *)obstack_next_free (string_obstack) - 1) = '\0';
+  XSTR (mnemonic_attr, 1) = XOBFINISH (string_obstack, char *);
 }
 
 /* Check if there are DEFINE_ATTRs with the same name.  */
diff --git a/gcc/read-md.c b/gcc/read-md.c
index e158be5..a4da3d3 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "errors.h"
+#include "statistics.h"
+#include "vec.h"
 #include "read-md.h"
 
 /* Associates PTR (which can be a string, etc.) with the file location
@@ -31,25 +33,6 @@ struct ptr_loc {
   int lineno;
 };
 
-/* Obstack used for allocating MD strings.  */
-struct obstack string_obstack;
-
-/* A table of ptr_locs, hashed on the PTR field.  */
-static htab_t ptr_locs;
-
-/* An obstack for the above.  Plain xmalloc is a bit heavyweight for a
-   small structure like ptr_loc.  */
-static struct obstack ptr_loc_obstack;
-
-/* A hash table of triples (A, B, C), where each of A, B and C is a condition
-   and A is equivalent to "B && C".  This is used to keep track of the source
-   of conditions that are made up of separate MD strings (such as the split
-   condition of a define_insn_and_split).  */
-static htab_t joined_conditions;
-
-/* An obstack for allocating joined_conditions entries.  */
-static struct obstack joined_conditions_obstack;
-
 /* This callback will be invoked whenever an md include directive is
    processed.  To be used for creation of the dependency file.  */
 void (*include_callback) (const char *);
@@ -58,13 +41,6 @@ void (*include_callback) (const char *);
 
 rtx_reader *rtx_reader_ptr;
 
-/* A table of md_constant structures, hashed by name.  Null if no
-   constant expansion should occur.  */
-static htab_t md_constants;
-
-/* A table of enum_type structures, hashed by name.  */
-static htab_t enum_types;
-
 /* Given an object that starts with a char * name field, return a hash
    code for its name.  */
 
@@ -102,26 +78,26 @@ leading_ptr_eq_p (const void *def1, const void *def2)
 
 /* Associate PTR with the file position given by FILENAME and LINENO.  */
 
-static void
-set_md_ptr_loc (const void *ptr, const char *filename, int lineno)
+void
+rtx_reader::set_md_ptr_loc (const void *ptr, const char *filename, int lineno)
 {
   struct ptr_loc *loc;
 
-  loc = (struct ptr_loc *) obstack_alloc (&ptr_loc_obstack,
+  loc = (struct ptr_loc *) obstack_alloc (&m_ptr_loc_obstack,
 					  sizeof (struct ptr_loc));
   loc->ptr = ptr;
   loc->filename = filename;
   loc->lineno = lineno;
-  *htab_find_slot (ptr_locs, loc, INSERT) = loc;
+  *htab_find_slot (m_ptr_locs, loc, INSERT) = loc;
 }
 
 /* Return the position associated with pointer PTR.  Return null if no
    position was set.  */
 
-static const struct ptr_loc *
-get_md_ptr_loc (const void *ptr)
+const struct ptr_loc *
+rtx_reader::get_md_ptr_loc (const void *ptr)
 {
-  return (const struct ptr_loc *) htab_find (ptr_locs, &ptr);
+  return (const struct ptr_loc *) htab_find (m_ptr_locs, &ptr);
 }
 
 /* Associate NEW_PTR with the same file position as OLD_PTR.  */
@@ -129,9 +105,9 @@ get_md_ptr_loc (const void *ptr)
 void
 copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
 {
-  const struct ptr_loc *loc = get_md_ptr_loc (old_ptr);
+  const struct ptr_loc *loc = rtx_reader_ptr->get_md_ptr_loc (old_ptr);
   if (loc != 0)
-    set_md_ptr_loc (new_ptr, loc->filename, loc->lineno);
+    rtx_reader_ptr->set_md_ptr_loc (new_ptr, loc->filename, loc->lineno);
 }
 
 /* If PTR is associated with a known file position, print a #line
@@ -140,7 +116,7 @@ copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
 void
 fprint_md_ptr_loc (FILE *outf, const void *ptr)
 {
-  const struct ptr_loc *loc = get_md_ptr_loc (ptr);
+  const struct ptr_loc *loc = rtx_reader_ptr->get_md_ptr_loc (ptr);
   if (loc != 0)
     fprintf (outf, "#line %d \"%s\"\n", loc->lineno, loc->filename);
 }
@@ -156,7 +132,7 @@ print_md_ptr_loc (const void *ptr)
    may be null or empty.  */
 
 const char *
-join_c_conditions (const char *cond1, const char *cond2)
+rtx_reader::join_c_conditions (const char *cond1, const char *cond2)
 {
   char *result;
   const void **entry;
@@ -171,23 +147,32 @@ join_c_conditions (const char *cond1, const char *cond2)
     return cond1;
 
   result = concat ("(", cond1, ") && (", cond2, ")", NULL);
-  obstack_ptr_grow (&joined_conditions_obstack, result);
-  obstack_ptr_grow (&joined_conditions_obstack, cond1);
-  obstack_ptr_grow (&joined_conditions_obstack, cond2);
-  entry = XOBFINISH (&joined_conditions_obstack, const void **);
-  *htab_find_slot (joined_conditions, entry, INSERT) = entry;
+  obstack_ptr_grow (&m_joined_conditions_obstack, result);
+  obstack_ptr_grow (&m_joined_conditions_obstack, cond1);
+  obstack_ptr_grow (&m_joined_conditions_obstack, cond2);
+  entry = XOBFINISH (&m_joined_conditions_obstack, const void **);
+  *htab_find_slot (m_joined_conditions, entry, INSERT) = entry;
   return result;
 }
 
+/* As rtx_reader::join_c_conditions above, but call it on the singleton
+   rtx_reader instance.  */
+
+const char *
+join_c_conditions (const char *cond1, const char *cond2)
+{
+  return rtx_reader_ptr->join_c_conditions (cond1, cond2);
+}
+
 /* Print condition COND to OUTF, wrapped in brackets.  If COND was created
    by join_c_conditions, recursively invoke this function for the original
    conditions and join the result with "&&".  Otherwise print a #line
    directive for COND if its original file position is known.  */
 
 void
-fprint_c_condition (FILE *outf, const char *cond)
+rtx_reader::fprint_c_condition (FILE *outf, const char *cond)
 {
-  const char **halves = (const char **) htab_find (joined_conditions, &cond);
+  const char **halves = (const char **) htab_find (m_joined_conditions, &cond);
   if (halves != 0)
     {
       fprintf (outf, "(");
@@ -204,6 +189,15 @@ fprint_c_condition (FILE *outf, const char *cond)
     }
 }
 
+/* As rtx_reader::fprint_c_condition above, but call it on the singleton
+   rtx_reader instance.  */
+
+void
+fprint_c_condition (FILE *outf, const char *cond)
+{
+  rtx_reader_ptr->fprint_c_condition (outf, cond);
+}
+
 /* Special fprint_c_condition for writing to STDOUT.  */
 
 void
@@ -414,7 +408,7 @@ rtx_reader::unread_char (int ch)
    punctuation chars of rtx printed syntax.  */
 
 void
-read_name (struct md_name *name)
+rtx_reader::read_name (struct md_name *name)
 {
   int c;
   size_t i;
@@ -458,7 +452,7 @@ read_name (struct md_name *name)
   name->buffer[i] = 0;
   name->string = name->buffer;
 
-  if (md_constants)
+  if (m_md_constants)
     {
       /* Do constant expansion.  */
       struct md_constant *def;
@@ -468,7 +462,7 @@ read_name (struct md_name *name)
 	  struct md_constant tmp_def;
 
 	  tmp_def.name = name->string;
-	  def = (struct md_constant *) htab_find (md_constants, &tmp_def);
+	  def = (struct md_constant *) htab_find (m_md_constants, &tmp_def);
 	  if (def)
 	    name->string = def->value;
 	}
@@ -479,8 +473,8 @@ read_name (struct md_name *name)
 /* Subroutine of the string readers.  Handles backslash escapes.
    Caller has read the backslash, but not placed it into the obstack.  */
 
-static void
-read_escape (void)
+void
+rtx_reader::read_escape ()
 {
   int c = read_char ();
 
@@ -508,32 +502,32 @@ read_escape (void)
     case 'a': case 'b': case 'f': case 'n': case 'r': case 't': case 'v':
     case '0': case '1': case '2': case '3': case '4': case '5': case '6':
     case '7': case 'x':
-      obstack_1grow (&string_obstack, '\\');
+      obstack_1grow (&m_string_obstack, '\\');
       break;
 
       /* \; makes stuff for a C string constant containing
 	 newline and tab.  */
     case ';':
-      obstack_grow (&string_obstack, "\\n\\t", 4);
+      obstack_grow (&m_string_obstack, "\\n\\t", 4);
       return;
 
       /* pass anything else through, but issue a warning.  */
     default:
       fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
-	       rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+	       get_filename (), get_lineno (),
 	       c);
-      obstack_1grow (&string_obstack, '\\');
+      obstack_1grow (&m_string_obstack, '\\');
       break;
     }
 
-  obstack_1grow (&string_obstack, c);
+  obstack_1grow (&m_string_obstack, c);
 }
 
 /* Read a double-quoted string onto the obstack.  Caller has scanned
    the leading quote.  */
 
 char *
-read_quoted_string (void)
+rtx_reader::read_quoted_string ()
 {
   int c;
 
@@ -548,25 +542,25 @@ read_quoted_string (void)
       else if (c == '"' || c == EOF)
 	break;
 
-      obstack_1grow (&string_obstack, c);
+      obstack_1grow (&m_string_obstack, c);
     }
 
-  obstack_1grow (&string_obstack, 0);
-  return XOBFINISH (&string_obstack, char *);
+  obstack_1grow (&m_string_obstack, 0);
+  return XOBFINISH (&m_string_obstack, char *);
 }
 
 /* Read a braced string (a la Tcl) onto the string obstack.  Caller
    has scanned the leading brace.  Note that unlike quoted strings,
    the outermost braces _are_ included in the string constant.  */
 
-static char *
-read_braced_string (void)
+char *
+rtx_reader::read_braced_string ()
 {
   int c;
   int brace_depth = 1;  /* caller-processed */
-  unsigned long starting_read_md_lineno = rtx_reader_ptr->get_lineno ();
+  unsigned long starting_read_md_lineno = get_lineno ();
 
-  obstack_1grow (&string_obstack, '{');
+  obstack_1grow (&m_string_obstack, '{');
   while (brace_depth)
     {
       c = read_char (); /* Read the string  */
@@ -585,11 +579,11 @@ read_braced_string (void)
 	  ("missing closing } for opening brace on line %lu",
 	   starting_read_md_lineno);
 
-      obstack_1grow (&string_obstack, c);
+      obstack_1grow (&m_string_obstack, c);
     }
 
-  obstack_1grow (&string_obstack, 0);
-  return XOBFINISH (&string_obstack, char *);
+  obstack_1grow (&m_string_obstack, 0);
+  return XOBFINISH (&m_string_obstack, char *);
 }
 
 /* Read some kind of string constant.  This is the high-level routine
@@ -597,7 +591,7 @@ read_braced_string (void)
    and dispatch to the appropriate string constant reader.  */
 
 char *
-read_string (int star_if_braced)
+rtx_reader::read_string (int star_if_braced)
 {
   char *stringbuf;
   int saw_paren = 0;
@@ -610,13 +604,13 @@ read_string (int star_if_braced)
       c = read_skip_spaces ();
     }
 
-  old_lineno = rtx_reader_ptr->get_lineno ();
+  old_lineno = get_lineno ();
   if (c == '"')
     stringbuf = read_quoted_string ();
   else if (c == '{')
     {
       if (star_if_braced)
-	obstack_1grow (&string_obstack, '*');
+	obstack_1grow (&m_string_obstack, '*');
       stringbuf = read_braced_string ();
     }
   else
@@ -625,15 +619,15 @@ read_string (int star_if_braced)
   if (saw_paren)
     require_char_ws (')');
 
-  set_md_ptr_loc (stringbuf, rtx_reader_ptr->get_filename (), old_lineno);
+  set_md_ptr_loc (stringbuf, get_filename (), old_lineno);
   return stringbuf;
 }
 
 /* Skip the rest of a construct that started at line LINENO and that
    is currently nested by DEPTH levels of parentheses.  */
 
-static void
-read_skip_construct (int depth, file_location loc)
+void
+rtx_reader::read_skip_construct (int depth, file_location loc)
 {
   struct md_name name;
   int c;
@@ -774,8 +768,8 @@ add_constant (htab_t defs, char *name, char *value,
 /* Process a define_constants directive, starting with the optional space
    after the "define_constants".  */
 
-static void
-handle_constants (void)
+void
+rtx_reader::handle_constants ()
 {
   int c;
   htab_t defs;
@@ -783,8 +777,8 @@ handle_constants (void)
   require_char_ws ('[');
 
   /* Disable constant expansion during definition processing.  */
-  defs = md_constants;
-  md_constants = 0;
+  defs = m_md_constants;
+  m_md_constants = 0;
   while ( (c = read_skip_spaces ()) != ']')
     {
       struct md_name name, value;
@@ -798,7 +792,7 @@ handle_constants (void)
 
       require_char_ws (')');
     }
-  md_constants = defs;
+  m_md_constants = defs;
 }
 
 /* For every constant definition, call CALLBACK with two arguments:
@@ -808,7 +802,7 @@ handle_constants (void)
 void
 traverse_md_constants (htab_trav callback, void *info)
 {
-  htab_traverse (md_constants, callback, info);
+  htab_traverse (rtx_reader_ptr->get_md_constants (), callback, info);
 }
 
 /* Return a malloc()ed decimal string that represents number NUMBER.  */
@@ -828,8 +822,8 @@ md_decimal_string (int number)
    number on which the directive started and MD_P is true if the
    directive is a define_enum rather than a define_c_enum.  */
 
-static void
-handle_enum (file_location loc, bool md_p)
+void
+rtx_reader::handle_enum (file_location loc, bool md_p)
 {
   char *enum_name, *value_name;
   struct md_name name;
@@ -839,7 +833,7 @@ handle_enum (file_location loc, bool md_p)
   int c;
 
   enum_name = read_string (false);
-  slot = htab_find_slot (enum_types, &enum_name, INSERT);
+  slot = htab_find_slot (m_enum_types, &enum_name, INSERT);
   if (*slot)
     {
       def = (struct enum_type *) *slot;
@@ -883,7 +877,7 @@ handle_enum (file_location loc, bool md_p)
 	  value_name = xstrdup (name.string);
 	  ev->name = value_name;
 	}
-      ev->def = add_constant (md_constants, value_name,
+      ev->def = add_constant (get_md_constants (), value_name,
 			      md_decimal_string (def->num_values), def);
 
       *def->tail_ptr = ev;
@@ -895,9 +889,9 @@ handle_enum (file_location loc, bool md_p)
 /* Try to find the definition of the given enum.  Return null on failure.  */
 
 struct enum_type *
-lookup_enum_type (const char *name)
+rtx_reader::lookup_enum_type (const char *name)
 {
-  return (struct enum_type *) htab_find (enum_types, &name);
+  return (struct enum_type *) htab_find (m_enum_types, &name);
 }
 
 /* For every enum definition, call CALLBACK with two arguments:
@@ -905,9 +899,9 @@ lookup_enum_type (const char *name)
    returns zero.  */
 
 void
-traverse_enum_types (htab_trav callback, void *info)
+rtx_reader::traverse_enum_types (htab_trav callback, void *info)
 {
-  htab_traverse (enum_types, callback, info);
+  htab_traverse (m_enum_types, callback, info);
 }
 
 
@@ -925,12 +919,43 @@ rtx_reader::rtx_reader ()
 {
   /* Set the global singleton pointer.  */
   rtx_reader_ptr = this;
+
+  obstack_init (&m_string_obstack);
+
+  m_ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
+  obstack_init (&m_ptr_loc_obstack);
+
+  m_joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
+  obstack_init (&m_joined_conditions_obstack);
+
+  m_md_constants = htab_create (31, leading_string_hash,
+				leading_string_eq_p, (htab_del) 0);
+
+  m_enum_types = htab_create (31, leading_string_hash,
+			      leading_string_eq_p, (htab_del) 0);
+
+  /* Unlock the stdio streams.  */
+  unlock_std_streams ();
 }
 
 /* rtx_reader's destructor.  */
 
 rtx_reader::~rtx_reader ()
 {
+  free (m_base_dir);
+
+  htab_delete (m_enum_types);
+
+  htab_delete (m_md_constants);
+
+  obstack_free (&m_joined_conditions_obstack, NULL);
+  htab_delete (m_joined_conditions);
+
+  obstack_free (&m_ptr_loc_obstack, NULL);
+  htab_delete (m_ptr_locs);
+
+  obstack_free (&m_string_obstack, NULL);
+
   /* Clear the global singleton pointer.  */
   rtx_reader_ptr = NULL;
 }
@@ -1105,20 +1130,6 @@ rtx_reader::read_md_files (int argc, const char **argv,
   bool already_read_stdin;
   int num_files;
 
-  /* Initialize global data.  */
-  obstack_init (&string_obstack);
-  ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
-  obstack_init (&ptr_loc_obstack);
-  joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
-  obstack_init (&joined_conditions_obstack);
-  md_constants = htab_create (31, leading_string_hash,
-			      leading_string_eq_p, (htab_del) 0);
-  enum_types = htab_create (31, leading_string_hash,
-			    leading_string_eq_p, (htab_del) 0);
-
-  /* Unlock the stdio streams.  */
-  unlock_std_streams ();
-
   /* First we loop over all the options.  */
   for (i = 1; i < argc; i++)
     if (argv[i][0] == '-')
diff --git a/gcc/read-md.h b/gcc/read-md.h
index a74cc72..a089595 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -107,14 +107,49 @@ class rtx_reader
 
   file_location get_current_location () const;
 
+  /* Defined in read-md.c.  */
   int read_char (void);
   void unread_char (int ch);
+  void read_name (struct md_name *name);
+  void read_escape ();
+  char *read_quoted_string ();
+  char *read_braced_string ();
+  char *read_string (int star_if_braced);
+  void read_skip_construct (int depth, file_location loc);
+
+  void set_md_ptr_loc (const void *ptr, const char *filename, int lineno);
+  const struct ptr_loc *get_md_ptr_loc (const void *ptr);
+
+  struct enum_type *lookup_enum_type (const char *name);
+  void traverse_enum_types (htab_trav callback, void *info);
+
+  void handle_constants ();
+  void handle_enum (file_location loc, bool md_p);
+
+  const char *join_c_conditions (const char *cond1, const char *cond2);
+  void fprint_c_condition (FILE *outf, const char *cond);
+
+  /* Defined in read-rtl.c.  */
+  const char *apply_iterator_to_string (const char *string);
+  rtx copy_rtx_for_iterators (rtx original);
+  void read_conditions ();
+  void record_potential_iterator_use (struct iterator_group *group,
+				      void *ptr, const char *name);
+  struct mapping *read_mapping (struct iterator_group *group, htab_t table);
+  bool read_rtx (const char *rtx_name, vec<rtx> *rtxen);
+  rtx read_rtx_code (const char *code_name);
+  void read_rtx_operand (rtx return_rtx, int idx);
+  rtx read_nested_rtx ();
+  rtx read_rtx_variadic (rtx form);
 
   const char *get_top_level_filename () const { return m_toplevel_fname; }
   const char *get_filename () const { return m_read_md_filename; }
   int get_lineno () const { return m_read_md_lineno; }
   int get_colno () const { return m_read_md_colno; }
 
+  struct obstack *get_string_obstack () { return &m_string_obstack; }
+  htab_t get_md_constants () { return m_md_constants; }
+
  private:
   /* A singly-linked list of filenames.  */
   struct file_name_list {
@@ -159,6 +194,32 @@ class rtx_reader
 
   /* A pointer to the null terminator of the md include chain.  */
   file_name_list **m_last_dir_md_include_ptr;
+
+  /* Obstack used for allocating MD strings.  */
+  struct obstack m_string_obstack;
+
+  /* A table of ptr_locs, hashed on the PTR field.  */
+  htab_t m_ptr_locs;
+
+  /* An obstack for the above.  Plain xmalloc is a bit heavyweight for a
+     small structure like ptr_loc.  */
+  struct obstack m_ptr_loc_obstack;
+
+  /* A hash table of triples (A, B, C), where each of A, B and C is a condition
+     and A is equivalent to "B && C".  This is used to keep track of the source
+     of conditions that are made up of separate MD strings (such as the split
+     condition of a define_insn_and_split).  */
+  htab_t m_joined_conditions;
+
+  /* An obstack for allocating joined_conditions entries.  */
+  struct obstack m_joined_conditions_obstack;
+
+  /* A table of md_constant structures, hashed by name.  Null if no
+     constant expansion should occur.  */
+  htab_t m_md_constants;
+
+  /* A table of enum_type structures, hashed by name.  */
+  htab_t m_enum_types;
 };
 
 /* Global singleton.  */
@@ -175,7 +236,6 @@ class noop_reader : public rtx_reader
   void handle_unknown_directive (file_location, const char *);
 };
 
-extern struct obstack string_obstack;
 extern void (*include_callback) (const char *);
 
 /* Read the next character from the MD file.  */
@@ -198,7 +258,6 @@ extern hashval_t leading_string_hash (const void *);
 extern int leading_string_eq_p (const void *, const void *);
 extern void copy_md_ptr_loc (const void *, const void *);
 extern void print_md_ptr_loc (const void *);
-extern void fprint_md_ptr_loc (FILE *, const void *);
 extern const char *join_c_conditions (const char *, const char *);
 extern void print_c_condition (const char *);
 extern void fprint_c_condition (FILE *, const char *);
@@ -210,9 +269,6 @@ extern void fatal_with_file_and_line (const char *, ...)
 extern void fatal_expected_char (int, int) ATTRIBUTE_NORETURN;
 extern int read_skip_spaces (void);
 extern void require_char_ws (char expected);
-extern void read_name (struct md_name *);
-extern char *read_quoted_string (void);
-extern char *read_string (int);
 extern int n_comma_elts (const char *);
 extern const char *scan_comma_elt (const char **);
 extern void upcase_string (char *);
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 925ea45..c3c0b93 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -106,10 +106,6 @@ htab_t subst_attr_to_iter_map = NULL;
 const char *current_iterator_name;
 
 static void validate_const_int (const char *);
-static rtx read_rtx_code (const char *);
-static void read_rtx_operand (rtx, int);
-static rtx read_nested_rtx (void);
-static rtx read_rtx_variadic (rtx);
 
 /* The mode and code iterator structures.  */
 static struct iterator_group modes, codes, ints, substs;
@@ -329,8 +325,8 @@ map_attr_string (const char *p)
 /* Apply the current iterator values to STRING.  Return the new string
    if any changes were needed, otherwise return STRING itself.  */
 
-static const char *
-apply_iterator_to_string (const char *string)
+const char *
+rtx_reader::apply_iterator_to_string (const char *string)
 {
   char *base, *copy, *p, *start, *end;
   struct map_value *v;
@@ -351,14 +347,14 @@ apply_iterator_to_string (const char *string)
 
       /* Add everything between the last copied byte and the '<',
 	 then add in the attribute value.  */
-      obstack_grow (&string_obstack, base, start - base);
-      obstack_grow (&string_obstack, v->string, strlen (v->string));
+      obstack_grow (&m_string_obstack, base, start - base);
+      obstack_grow (&m_string_obstack, v->string, strlen (v->string));
       base = end + 1;
     }
   if (base != copy)
     {
-      obstack_grow (&string_obstack, base, strlen (base) + 1);
-      copy = XOBFINISH (&string_obstack, char *);
+      obstack_grow (&m_string_obstack, base, strlen (base) + 1);
+      copy = XOBFINISH (&m_string_obstack, char *);
       copy_md_ptr_loc (copy, string);
       return copy;
     }
@@ -368,8 +364,8 @@ apply_iterator_to_string (const char *string)
 /* Return a deep copy of X, substituting the current iterator
    values into any strings.  */
 
-static rtx
-copy_rtx_for_iterators (rtx original)
+rtx
+rtx_reader::copy_rtx_for_iterators (rtx original)
 {
   const char *format_ptr, *p;
   int i, j;
@@ -546,7 +542,7 @@ apply_iterators (rtx original, vec<rtx> *queue)
 	  condition = join_c_conditions (condition, v->string);
 	}
       apply_attribute_uses ();
-      x = copy_rtx_for_iterators (original);
+      x = rtx_reader_ptr->copy_rtx_for_iterators (original);
       add_condition_to_rtx (x, condition);
 
       /* We apply subst iterator after RTL-template is copied, as during
@@ -738,8 +734,8 @@ atoll (const char *p)
    generated by (the program generated by) genconditions.c, and
    slipped in at the beginning of the sequence of MD files read by
    most of the other generators.  */
-static void
-read_conditions (void)
+void
+rtx_reader::read_conditions ()
 {
   int c;
 
@@ -837,9 +833,9 @@ record_attribute_use (struct iterator_group *group, void *ptr,
    for group GROUP.  PTR is the value to pass to GROUP's apply_iterator
    callback.  */
 
-static void
-record_potential_iterator_use (struct iterator_group *group, void *ptr,
-			       const char *name)
+void
+rtx_reader::record_potential_iterator_use (struct iterator_group *group,
+					   void *ptr, const char *name)
 {
   struct mapping *m;
   size_t len;
@@ -849,8 +845,8 @@ record_potential_iterator_use (struct iterator_group *group, void *ptr,
     {
       /* Copy the attribute string into permanent storage, without the
 	 angle brackets around it.  */
-      obstack_grow0 (&string_obstack, name + 1, len - 2);
-      record_attribute_use (group, ptr, XOBFINISH (&string_obstack, char *));
+      obstack_grow0 (&m_string_obstack, name + 1, len - 2);
+      record_attribute_use (group, ptr, XOBFINISH (&m_string_obstack, char *));
     }
   else
     {
@@ -872,8 +868,8 @@ record_potential_iterator_use (struct iterator_group *group, void *ptr,
    Represent the declaration as a "mapping" structure; add it to TABLE
    (which belongs to GROUP) and return it.  */
 
-static struct mapping *
-read_mapping (struct iterator_group *group, htab_t table)
+struct mapping *
+rtx_reader::read_mapping (struct iterator_group *group, htab_t table)
 {
   struct md_name name;
   struct mapping *m;
@@ -974,7 +970,7 @@ read_subst_mapping (htab_t subst_iters_table, htab_t subst_attrs_table,
   int i;
 
   for (i = 0; i < 4; i++)
-    attr_operands[i] = read_string (false);
+    attr_operands[i] = rtx_reader_ptr->read_string (false);
 
   add_define_subst_attr (attr_operands, queue);
 
@@ -1019,7 +1015,7 @@ check_code_iterator (struct mapping *iterator)
    store the list of rtxes as an EXPR_LIST in *X.  */
 
 bool
-read_rtx (const char *rtx_name, vec<rtx> *rtxen)
+rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
 {
   static bool initialized = false;
 
@@ -1087,8 +1083,8 @@ read_rtx (const char *rtx_name, vec<rtx> *rtxen)
    either an rtx code or a code iterator.  Parse the rest of the rtx and
    return it.  */
 
-static rtx
-read_rtx_code (const char *code_name)
+rtx
+rtx_reader::read_rtx_code (const char *code_name)
 {
   RTX_CODE code;
   struct mapping *iterator;
@@ -1200,8 +1196,8 @@ read_rtx_code (const char *code_name)
    based on the corresponding format character within GET_RTX_FORMAT
    for the GET_CODE (RETURN_RTX).  */
 
-static void
-read_rtx_operand (rtx return_rtx, int idx)
+void
+rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
 {
   RTX_CODE code = GET_CODE (return_rtx);
   const char *format_ptr = GET_RTX_FORMAT (code);
@@ -1304,17 +1300,17 @@ read_rtx_operand (rtx return_rtx, int idx)
 		|| GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
 	  {
 	    char line_name[20];
-	    const char *read_md_filename = rtx_reader_ptr->get_filename ();
+	    const char *read_md_filename = get_filename ();
 	    const char *fn = (read_md_filename ? read_md_filename : "rtx");
 	    const char *slash;
 	    for (slash = fn; *slash; slash ++)
 	      if (*slash == '/' || *slash == '\\' || *slash == ':')
 		fn = slash + 1;
-	    obstack_1grow (&string_obstack, '*');
-	    obstack_grow (&string_obstack, fn, strlen (fn));
-	    sprintf (line_name, ":%d", rtx_reader_ptr->get_lineno ());
-	    obstack_grow (&string_obstack, line_name, strlen (line_name)+1);
-	    stringbuf = XOBFINISH (&string_obstack, char *);
+	    obstack_1grow (&m_string_obstack, '*');
+	    obstack_grow (&m_string_obstack, fn, strlen (fn));
+	    sprintf (line_name, ":%d", get_lineno ());
+	    obstack_grow (&m_string_obstack, line_name, strlen (line_name)+1);
+	    stringbuf = XOBFINISH (&m_string_obstack, char *);
 	  }
 
 	/* Find attr-names in the string.  */
@@ -1402,8 +1398,8 @@ read_rtx_operand (rtx return_rtx, int idx)
 
 /* Read a nested rtx construct from the MD file and return it.  */
 
-static rtx
-read_nested_rtx (void)
+rtx
+rtx_reader::read_nested_rtx ()
 {
   struct md_name name;
   rtx return_rtx;
@@ -1427,8 +1423,8 @@ read_nested_rtx (void)
    When called, FORM is (thing x1 x2), and the file position
    is just past the leading parenthesis of x3.  Only works
    for THINGs which are dyadic expressions, e.g. AND, IOR.  */
-static rtx
-read_rtx_variadic (rtx form)
+rtx
+rtx_reader::read_rtx_variadic (rtx form)
 {
   char c = '(';
   rtx p = form, q;
-- 
1.8.5.3

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

* Re: [PATCH] Add "__RTL" to cc1 (v2)
  2016-10-13 13:49       ` Richard Biener
  2016-10-13 13:52         ` Bernd Schmidt
@ 2016-10-14 19:23         ` David Malcolm
  1 sibling, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-14 19:23 UTC (permalink / raw)
  To: Richard Biener; +Cc: Joseph Myers, GCC Patches

On Thu, 2016-10-13 at 15:49 +0200, Richard Biener wrote:
> On Fri, Oct 7, 2016 at 5:58 PM, David Malcolm <dmalcolm@redhat.com>
> wrote:
> > On Wed, 2016-10-05 at 16:09 +0000, Joseph Myers wrote:
> > > On Wed, 5 Oct 2016, David Malcolm wrote:
> > > 
> > > > @@ -1752,6 +1759,35 @@ c_parser_declaration_or_fndef (c_parser
> > > > *parser, bool fndef_ok,
> > > >        c_parser_skip_to_end_of_block_or_statement (parser);
> > > >        return;
> > > >      }
> > > > +
> > > > +  if (c_parser_next_token_is (parser, CPP_KEYWORD))
> > > > +    {
> > > > +      c_token *kw_token = c_parser_peek_token (parser);
> > > > +      if (kw_token->keyword == RID_RTL)
> > > 
> > > if (c_parser_next_token_is_keyword (parser, RID_RTL))
> > > 
> > > You're missing an update to the comment above this function to
> > > show
> > > what
> > > the new syntax is.
> > 
> > Thanks.  Here's an updated version of the patch which fixes that,
> > along with some other fixes:
> > * Use c_parser_next_token_is_keyword.
> > * Removed a stray "FIXME".
> > * Removed some debug code.
> > * Add more comments
> > * Fixed a typo in the ChangeLog ("__RID" -> "__RTL")
> > 
> > Blurb from original version:
> > 
> > This patch implements Richi's idea of having a custom __RTL marker
> > in C function definitions, to indicate that the body of the
> > function
> > is to be parsed as RTL, rather than C:
> > 
> > int __RTL test_fn_1 (int i)
> > {
> >  (function "times_two"
> >    (insn-chain
> >      (note 1 0 4 (nil) NOTE_INSN_DELETED)
> >      ;; etc
> >    ) ;; insn-chain
> >    (crtl
> >      (return_rtx
> >        (reg/i:SI 0 ax)
> >      ) ;; return_rtx
> >    ) ;; crtl
> >   ) ;; function
> > }
> > 
> > This allows for decls and types to be declared in C, and to use
> > the function decl from the C frontend.
> > 
> > I added support for running a single pass by giving __RTL an
> > optional
> > parameter (the name of the pass).  For example:
> 
> So what's the default behavior?

Currently it loads the RTL, but doesn't manage to generate assembler
for it.  There are some state issues to be tracked down.

int __RTL ("rtl-dfinit") test_fn_2 (int i)
> > {
> >  (function "times_two"
> >    (insn-chain
> >      (note 1 0 4 (nil) NOTE_INSN_DELETED)
> >      ;; etc
> >    ) ;; insn-chain
> >    (crtl
> >      (return_rtx
> >        (reg/i:SI 0 ax)
> >      ) ;; return_rtx
> >    ) ;; crtl
> >   ) ;; function
> > }
> 
> Does it really run a single pass only? 

Yes.

>  Thus you can't do a { dg-do run } test
> with __RTL?  

Currently not, but I think I can fix that.

> The GIMPLE FE has a __GIMPLE (starts-with: "pass") thing
> starting from a specific pass but going all the way to assembly
> output.

It strikes me that we might need that; we probably need some way to
identify what state the RTL is in.

> It looks like your run-one-rtl-pass thingy is directly invoked from
> the "frontend"
> rather than passing down everything to the middle-end?

Yes.  There are some nasty state issues here: the whole of the RTL
-handling in the backend seems to expect a single function, and various
other singleton state (e.g. "crtl" aka "x_rtl").  The RTL "frontend" is
populating that state directly, so I think I have to do one function at
a time, running any/all RTL passes as soon as each one is parsed.

[...]

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

* Re: [PATCH] Add "__RTL" to cc1 (v2)
  2016-10-14  9:33           ` Richard Biener
  2016-10-14  9:48             ` Bernd Schmidt
@ 2016-10-14 19:25             ` David Malcolm
  2016-10-14 19:27               ` Bernd Schmidt
  1 sibling, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-14 19:25 UTC (permalink / raw)
  To: Richard Biener, Bernd Schmidt; +Cc: Joseph Myers, GCC Patches

On Fri, 2016-10-14 at 11:33 +0200, Richard Biener wrote:
> On Thu, Oct 13, 2016 at 3:51 PM, Bernd Schmidt <bschmidt@redhat.com>
> wrote:
> > On 10/13/2016 03:49 PM, Richard Biener wrote:
> > > 
> > > Does it really run a single pass only?  Thus you can't do a { dg
> > > -do run }
> > > test
> > > with __RTL?
> > 
> > 
> > I think that's really not the intended use-case. To my mind this is
> > for
> > unit-testing: ensuring that a given rtl pass performs the expected
> > transformation on an input.
> 
> Ok, so at least for the GIMPLE FE side I thought it's useful to allow
> a correctness verification with something simpler than pattern
> matching
> on the pass output.  By means of doing runtime verification of an
> expected
> result (this necessarily includes running followup passes as we have
> to
> generate code).  I don't see why this shouldn't apply to __RTL -- it
> might
> be more difficult to get __RTL testcases to the point where they emit
> assembly of course.
> 
> OTOH the question then still is what's the default behavior if you do
> _not_
> specify a "single pass to run".

As noted elsewhere, the current behavior is that it merely parses the
function and ignores it - and that's a bug in the current
implementation.

The behavior probably should be that it runs the remainder of the RTL
passes from some specified point, and generates valid assembler (so
that we can have dg-do DejaGnu tests).

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

* Re: [PATCH] Add "__RTL" to cc1 (v2)
  2016-10-14 19:25             ` David Malcolm
@ 2016-10-14 19:27               ` Bernd Schmidt
  2016-10-14 19:35                 ` David Malcolm
  0 siblings, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-14 19:27 UTC (permalink / raw)
  To: David Malcolm, Richard Biener; +Cc: Joseph Myers, GCC Patches

On 10/14/2016 09:25 PM, David Malcolm wrote:
>
> The behavior probably should be that it runs the remainder of the RTL
> passes from some specified point, and generates valid assembler (so
> that we can have dg-do DejaGnu tests).

Actually I had imagined that tests would specify before and after RTL so 
that we verify that the pass we're testing does what it's supposed to do.


Bernd

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

* Re: [PATCH] Add "__RTL" to cc1 (v2)
  2016-10-14 19:27               ` Bernd Schmidt
@ 2016-10-14 19:35                 ` David Malcolm
  0 siblings, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-14 19:35 UTC (permalink / raw)
  To: Bernd Schmidt, Richard Biener; +Cc: Joseph Myers, GCC Patches

On Fri, 2016-10-14 at 21:27 +0200, Bernd Schmidt wrote:
> On 10/14/2016 09:25 PM, David Malcolm wrote:
> > 
> > The behavior probably should be that it runs the remainder of the
> > RTL
> > passes from some specified point, and generates valid assembler (so
> > that we can have dg-do DejaGnu tests).
> 
> Actually I had imagined that tests would specify before and after RTL
> so 
> that we verify that the pass we're testing does what it's supposed to
> do.

Note that this approach would allow for:

  { dg-final { scan-rtl-dump "SOMETHING" "PASS OF INTEREST" } } */

directives in the .c file, so it would support specifying the "after
RTL" to some extent.

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

* [PATCH] (v2) Tweaks to print_rtx_function
  2016-10-13 14:18                       ` Bernd Schmidt
@ 2016-10-14 19:41                         ` David Malcolm
  2016-10-14 20:07                           ` Bernd Schmidt
  0 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-14 19:41 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm

On Thu, 2016-10-13 at 16:18 +0200, Bernd Schmidt wrote:
> On 10/13/2016 04:08 PM, David Malcolm wrote:
> > I thought it might be useful to brainstorm [1] some ideas on this,
> > so  here are various possible ways it could be printed for this use
> > -case:
> > 
> > * Offset by LAST_VIRTUAL_REGISTER + 1 (as in the patch), and
> > printed
> > just as a number, giving:
> > 
> >   (reg:SI 3)
> 
> Unambiguous in the compact format, nice low register numbers, but
> some
> potential for confusion with hard regs based on what people are used
> to.
> 
> > * Prefixed by a "sigil" character:
> 
>  >   (reg:SI %3)
> 
> Avoids the confusion issue and shouldn't overlap with hard register
> names. I think this is the one I prefer, followed by plain (reg:SI
> 3).
> 
> >   (reg:SI P3)
> 
> Can't use this, as there are machines with P3 registers.
> 
> > * Prefixed so it looks like a register name:
> > 
> >   (reg:SI pseudo-3)
> >   (reg:SI pseudo_3)
> >   (reg:SI pseudo+3)
> 
> Not too different from just a "%" prefix and probably too verbose.
> 
> > Looking at print_rtx_operand_code_r there are also things like
> > ORIGINAL_REGNO, REG_EXPR and REG_OFFSET which get printed after the
> > main regno, e.g.: >
> 
> >   (reg:SI 1 [ <retval> ])
> 
> That's the REG_EXPR here presumably? The interesting part comes when
> parsing this.

Indeed, but that seems like an issue for another patch...

Here's an updated version of the patch, which uses the '%' sigil for
non-virtual pseudos.

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.

OK for trunk?

gcc/ChangeLog:
	* print-rtl-function.c (print_edge): Omit "(flags)" when none are
	set.
	(print_rtx_function): Update example in comment for...
	* print-rtl.c (print_rtx_operand_code_r): In compact mode, print
	non-virtual pseudos with a '%' sigil followed by the regno, offset
	by (LAST_VIRTUAL_REGISTER + 1), so that the first non-virtual
	pseudo is dumped as "%0".
---
 gcc/print-rtl-function.c | 29 ++++++++++++++++++-----------
 gcc/print-rtl.c          |  8 ++++++++
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/gcc/print-rtl-function.c b/gcc/print-rtl-function.c
index 2abae84..f46304b 100644
--- a/gcc/print-rtl-function.c
+++ b/gcc/print-rtl-function.c
@@ -60,9 +60,11 @@ print_edge (FILE *outfile, edge e, bool from)
 
   /* Express edge flags as a string with " | " separator.
      e.g. (flags "FALLTHRU | DFS_BACK").  */
-  fprintf (outfile, " (flags \"");
-  bool seen_flag = false;
-#define DEF_EDGE_FLAG(NAME,IDX) \
+  if (e->flags)
+    {
+      fprintf (outfile, " (flags \"");
+      bool seen_flag = false;
+#define DEF_EDGE_FLAG(NAME,IDX)			\
   do {						\
     if (e->flags & EDGE_##NAME)			\
       {						\
@@ -75,7 +77,10 @@ print_edge (FILE *outfile, edge e, bool from)
 #include "cfg-flags.def"
 #undef DEF_EDGE_FLAG
 
-  fprintf (outfile, "\"))\n");
+      fprintf (outfile, "\")");
+    }
+
+  fprintf (outfile, ")\n");
 }
 
 /* If BB is non-NULL, print the start of a "(block)" directive for it
@@ -132,7 +137,9 @@ can_have_basic_block_p (const rtx_insn *insn)
    If COMPACT, then instructions are printed in a compact form:
    - INSN_UIDs are omitted, except for jumps and CODE_LABELs,
    - INSN_CODEs are omitted,
-   - register numbers are omitted for hard and virtual regs
+   - register numbers are omitted for hard and virtual regs, and
+     non-virtual pseudos are offset relative to the first such reg, and
+     printed with a '%' sigil e.g. "%0" for (LAST_VIRTUAL_REGISTER + 1),
    - insn names are prefixed with "c" (e.g. "cinsn", "cnote", etc)
 
    Example output (with COMPACT==true):
@@ -148,13 +155,13 @@ can_have_basic_block_p (const rtx_insn *insn)
 		       (reg:SI di [ i ])) "t.c":2
 		   (nil))
 	 (cnote NOTE_INSN_FUNCTION_BEG)
-	 (cinsn (set (reg:SI 89)
+	 (cinsn (set (reg:SI %2)
 		       (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
 			       (const_int -4)) [1 i+0 S4 A32])) "t.c":3
 		   (nil))
 	 (cinsn (parallel [
-			   (set (reg:SI 87 [ _2 ])
-			       (ashift:SI (reg:SI 89)
+			   (set (reg:SI %0 [ _2 ])
+			       (ashift:SI (reg:SI %2)
 				   (const_int 1)))
 			   (clobber (reg:CC flags))
 		       ]) "t.c":3
@@ -162,11 +169,11 @@ can_have_basic_block_p (const rtx_insn *insn)
 				   (const_int -4)) [1 i+0 S4 A32])
 			   (const_int 1))
 		       (nil)))
-	 (cinsn (set (reg:SI 88 [ <retval> ])
-		       (reg:SI 87 [ _2 ])) "t.c":3
+	 (cinsn (set (reg:SI %1 [ <retval> ])
+		       (reg:SI %0 [ _2 ])) "t.c":3
 		   (nil))
 	 (cinsn (set (reg/i:SI ax)
-		       (reg:SI 88 [ <retval> ])) "t.c":4
+		       (reg:SI %1 [ <retval> ])) "t.c":4
 		   (nil))
 	 (cinsn (use (reg/i:SI ax)) "t.c":4
 		   (nil))
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index f114cb4..46f3c4d 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -400,6 +400,14 @@ print_rtx_operand_code_r (const_rtx in_rtx)
 #endif
     if (flag_dump_unnumbered && is_insn)
       fputc ('#', outfile);
+    else if (flag_compact)
+      {
+	/* In compact mode, print pseudos with a '%' sigil following
+	   by the regno, offset by (LAST_VIRTUAL_REGISTER + 1), so that the
+	   first non-virtual pseudo is dumped as "%0".  */
+	gcc_assert (regno > LAST_VIRTUAL_REGISTER);
+	fprintf (outfile, " %%%d", regno - (LAST_VIRTUAL_REGISTER + 1));
+      }
     else
       fprintf (outfile, " %d", regno);
 
-- 
1.8.5.3

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

* Re: [PATCH] (v2) Tweaks to print_rtx_function
  2016-10-14 19:41                         ` [PATCH] (v2) " David Malcolm
@ 2016-10-14 20:07                           ` Bernd Schmidt
  0 siblings, 0 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-14 20:07 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/14/2016 10:12 PM, David Malcolm wrote:
> gcc/ChangeLog:
> 	* print-rtl-function.c (print_edge): Omit "(flags)" when none are
> 	set.
> 	(print_rtx_function): Update example in comment for...
> 	* print-rtl.c (print_rtx_operand_code_r): In compact mode, print
> 	non-virtual pseudos with a '%' sigil followed by the regno, offset
> 	by (LAST_VIRTUAL_REGISTER + 1), so that the first non-virtual
> 	pseudo is dumped as "%0".

Ok.


Bernd

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

* Re: [PATCH] read-md.c: Move various state to within class rtx_reader
  2016-10-14 17:45         ` [PATCH] read-md.c: Move various state to within class rtx_reader David Malcolm
@ 2016-10-17 11:05           ` Bernd Schmidt
  2016-10-17 11:37           ` Richard Sandiford
  1 sibling, 0 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-17 11:05 UTC (permalink / raw)
  To: David Malcolm, Richard Sandiford, gcc-patches

On 10/14/2016 08:16 PM, David Malcolm wrote:

> In this version of the patch, I've moved the global variables to
> be fields of class rtx_reader, moving their setup to the constructor.
> The patch adds matching cleanups to the destructor, along with a
> cleanup of m_base_dir.
>
> Doing so requires updating the various users of these fields.
> Where it seemed appropriate, I made the functions be methods
> of rtx_reader.  In other cases, I updated them to access the fields
> via rtx_reader_ptr.
>
> Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.

Well, at least the actual patch doesn't look as scary as the ChangeLog.

There are things one could discuss, like maybe gensupport should just 
have its own string obstack. But on the whole I think this is 
reasonable, so OK.


Bernd

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

* Re: [PATCH] read-md.c: Move various state to within class rtx_reader
  2016-10-14 17:45         ` [PATCH] read-md.c: Move various state to within class rtx_reader David Malcolm
  2016-10-17 11:05           ` Bernd Schmidt
@ 2016-10-17 11:37           ` Richard Sandiford
  2016-10-17 16:27             ` [PATCH] read-md.c: Move various state to within class rtx_reader (v3) David Malcolm
  1 sibling, 1 reply; 96+ messages in thread
From: Richard Sandiford @ 2016-10-17 11:37 UTC (permalink / raw)
  To: David Malcolm; +Cc: Bernd Schmidt, gcc-patches

David Malcolm <dmalcolm@redhat.com> writes:
> @@ -2388,8 +2389,10 @@ gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn)
>  static int
>  mnemonic_htab_callback (void **slot, void *info ATTRIBUTE_UNUSED)
>  {
> -  obstack_grow (&string_obstack, (char*)*slot, strlen ((char*)*slot));
> -  obstack_1grow (&string_obstack, ',');
> +  struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack ();
> +
> +  obstack_grow (string_obstack, (char*)*slot, strlen ((char*)*slot));
> +  obstack_1grow (string_obstack, ',');

The old code was missing a space after the cast.  Might be good to
add it while you're there.

> @@ -2470,8 +2474,8 @@ gen_mnemonic_attr (void)
>    htab_traverse (mnemonic_htab, mnemonic_htab_callback, NULL);
>  
>    /* Replace the last ',' with the zero end character.  */
> -  *((char *)obstack_next_free (&string_obstack) - 1) = '\0';
> -  XSTR (mnemonic_attr, 1) = XOBFINISH (&string_obstack, char *);
> +  *((char *)obstack_next_free (string_obstack) - 1) = '\0';
> +  XSTR (mnemonic_attr, 1) = XOBFINISH (string_obstack, char *);

Same here.

> @@ -129,9 +105,9 @@ get_md_ptr_loc (const void *ptr)
>  void
>  copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
>  {
> -  const struct ptr_loc *loc = get_md_ptr_loc (old_ptr);
> +  const struct ptr_loc *loc = rtx_reader_ptr->get_md_ptr_loc (old_ptr);
>    if (loc != 0)
> -    set_md_ptr_loc (new_ptr, loc->filename, loc->lineno);
> +    rtx_reader_ptr->set_md_ptr_loc (new_ptr, loc->filename, loc->lineno);
>  }

I suppose it's bikeshedding, but since you need access to an rtx_reader
to get and set the locations, it feels like the rtx_reader should be
a parameter here too.

> @@ -140,7 +116,7 @@ copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
>  void
>  fprint_md_ptr_loc (FILE *outf, const void *ptr)
>  {
> -  const struct ptr_loc *loc = get_md_ptr_loc (ptr);
> +  const struct ptr_loc *loc = rtx_reader_ptr->get_md_ptr_loc (ptr);
>    if (loc != 0)
>      fprintf (outf, "#line %d \"%s\"\n", loc->lineno, loc->filename);
>  }

Same here.

> +/* As rtx_reader::join_c_conditions above, but call it on the singleton
> +   rtx_reader instance.  */
> +
> +const char *
> +join_c_conditions (const char *cond1, const char *cond2)
> +{
> +  return rtx_reader_ptr->join_c_conditions (cond1, cond2);
> +}
> +

I think it'd be better to have the callers use the rtx_reader_ptr
explicitly.

In general I think it'd be better if the read-md.h interface itself
didn't rely on there being a singleton, other than providing the
rtx_reader_ptr variable.  It would then be easy to allow non-singleton
uses in future, without having to update gen* calls a second time.

> @@ -204,6 +189,15 @@ fprint_c_condition (FILE *outf, const char *cond)
>      }
>  }
>  
> +/* As rtx_reader::fprint_c_condition above, but call it on the singleton
> +   rtx_reader instance.  */
> +
> +void
> +fprint_c_condition (FILE *outf, const char *cond)
> +{
> +  rtx_reader_ptr->fprint_c_condition (outf, cond);
> +}
> +
>  /* Special fprint_c_condition for writing to STDOUT.  */
>  
>  void

Another instance of the above.

> @@ -808,7 +802,7 @@ handle_constants (void)
>  void
>  traverse_md_constants (htab_trav callback, void *info)
>  {
> -  htab_traverse (md_constants, callback, info);
> +  htab_traverse (rtx_reader_ptr->get_md_constants (), callback, info);
>  }

Here too.

I assume you didn't turn the functions above into member functions
because they aren't primitives.  OTOH it might seem inconsistent
to have things like traverse_enum_types as member functions but
traverse_md_constants not.

Thanks,
Richard

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

* [PATCH] read-md.c: Move various state to within class rtx_reader (v3)
  2016-10-17 11:37           ` Richard Sandiford
@ 2016-10-17 16:27             ` David Malcolm
  2016-10-17 20:23               ` Richard Sandiford
  0 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-17 16:27 UTC (permalink / raw)
  To: Richard Sandiford, Bernd Schmidt; +Cc: gcc-patches, David Malcolm

On Mon, 2016-10-17 at 12:37 +0100, Richard Sandiford wrote:
> David Malcolm <dmalcolm@redhat.com> writes:
> > @@ -2388,8 +2389,10 @@ gen_mnemonic_setattr (htab_t mnemonic_htab,
> > rtx insn)
> >  static int
> >  mnemonic_htab_callback (void **slot, void *info ATTRIBUTE_UNUSED)
> >  {
> > -  obstack_grow (&string_obstack, (char*)*slot, strlen
> > ((char*)*slot));
> > -  obstack_1grow (&string_obstack, ',');
> > +  struct obstack *string_obstack = rtx_reader_ptr
> > ->get_string_obstack ();
> > +
> > +  obstack_grow (string_obstack, (char*)*slot, strlen
> > ((char*)*slot));
> > +  obstack_1grow (string_obstack, ',');
> 
> The old code was missing a space after the cast.  Might be good to
> add it while you're there.

Fixed.

> > @@ -2470,8 +2474,8 @@ gen_mnemonic_attr (void)
> >    htab_traverse (mnemonic_htab, mnemonic_htab_callback, NULL);
> >  
> >    /* Replace the last ',' with the zero end character.  */
> > -  *((char *)obstack_next_free (&string_obstack) - 1) = '\0';
> > -  XSTR (mnemonic_attr, 1) = XOBFINISH (&string_obstack, char *);
> > +  *((char *)obstack_next_free (string_obstack) - 1) = '\0';
> > +  XSTR (mnemonic_attr, 1) = XOBFINISH (string_obstack, char *);
> 
> Same here.

Fixed.

> > @@ -129,9 +105,9 @@ get_md_ptr_loc (const void *ptr)
> >  void
> >  copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
> >  {
> > -  const struct ptr_loc *loc = get_md_ptr_loc (old_ptr);
> > +  const struct ptr_loc *loc = rtx_reader_ptr->get_md_ptr_loc
> > (old_ptr);
> >    if (loc != 0)
> > -    set_md_ptr_loc (new_ptr, loc->filename, loc->lineno);
> > +    rtx_reader_ptr->set_md_ptr_loc (new_ptr, loc->filename, loc
> > ->lineno);
> >  }
> 
> I suppose it's bikeshedding, but since you need access to an
> rtx_reader
> to get and set the locations, it feels like the rtx_reader should be
> a parameter here too.

In the attached patch I've converted it to a member function, so
that the param is the implicit "this".

> > @@ -140,7 +116,7 @@ copy_md_ptr_loc (const void *new_ptr, const
> > void *old_ptr)
> >  void
> >  fprint_md_ptr_loc (FILE *outf, const void *ptr)
> >  {
> > -  const struct ptr_loc *loc = get_md_ptr_loc (ptr);
> > +  const struct ptr_loc *loc = rtx_reader_ptr->get_md_ptr_loc
> > (ptr);
> >    if (loc != 0)
> >      fprintf (outf, "#line %d \"%s\"\n", loc->lineno, loc
> > ->filename);
> >  }
> 
> Same here.

Likewise, and for print_md_ptr_loc.

> > +/* As rtx_reader::join_c_conditions above, but call it on the
> > singleton
> > +   rtx_reader instance.  */
> > +
> > +const char *
> > +join_c_conditions (const char *cond1, const char *cond2)
> > +{
> > +  return rtx_reader_ptr->join_c_conditions (cond1, cond2);
> > +}
> > +
> 
> I think it'd be better to have the callers use the rtx_reader_ptr
> explicitly.
> 
> In general I think it'd be better if the read-md.h interface itself
> didn't rely on there being a singleton, other than providing the
> rtx_reader_ptr variable.  It would then be easy to allow non
> -singleton
> uses in future, without having to update gen* calls a second time.

OK
	
> > @@ -204,6 +189,15 @@ fprint_c_condition (FILE *outf, const char
> > *cond)
> >      }
> >  }
> >  
> > +/* As rtx_reader::fprint_c_condition above, but call it on the
> > singleton
> > +   rtx_reader instance.  */
> > +
> > +void
> > +fprint_c_condition (FILE *outf, const char *cond)
> > +{
> > +  rtx_reader_ptr->fprint_c_condition (outf, cond);
> > +}
> > +
> >  /* Special fprint_c_condition for writing to STDOUT.  */
> >  
> >  void
> 
> Another instance of the above.

Fixed.

> > @@ -808,7 +802,7 @@ handle_constants (void)
> >  void
> >  traverse_md_constants (htab_trav callback, void *info)
> >  {
> > -  htab_traverse (md_constants, callback, info);
> > +  htab_traverse (rtx_reader_ptr->get_md_constants (), callback,
> > info);
> >  }
> 
> Here too.
> 
> I assume you didn't turn the functions above into member functions
> because they aren't primitives.  OTOH it might seem inconsistent
> to have things like traverse_enum_types as member functions but
> traverse_md_constants not.

In the following I've converted traverse_md_constants to a member
function.

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.

OK for trunk?

gcc/ChangeLog:
	* genattrtab.c (attr_string): Use rtx_reader_ptr for call to
	copy_md_ptr_loc.
	(gen_attr): Use rtx_reader_ptr for lookup_enum_type call.
	(write_test_expr): Use rtx_reader_ptr for calls to
	fprint_c_condition.
	(write_attr_value): Likewise.
	* genconditions.c (write_one_condition): Use rtx_reader_ptr for
	call to print_md_ptr_loc.
	(write_one_condition): Likewise for calls to print_c_condition.
	* genconstants.c: Include "statistics.h" and "vec.h".
	(main): Update for conversion to member functions.
	* genemit.c (emit_c_code): Use rtx_reader_ptr for
	call to print_md_ptr_loc.
	* genenums.c: Include "statistics.h" and "vec.h".
	(main): Update for conversion of traverse_enum_types to a method.
	* genmddeps.c: Include "statistics.h" and "vec.h".
	* genoutput.c (process_template): Use rtx_reader_ptr for call to
	print_md_ptr_loc.
	* genpreds.c (write_predicate_subfunction): Likewise.
	(write_predicate_expr): Likewise for calls to print_c_condition.
	* genrecog.c (print_test): Likewise.
	* gensupport.c (process_rtx): Likewise for calls to
	copy_md_ptr_loc and join_c_conditions.
	(alter_test_for_insn): Likewise for call to join_c_conditions.
	(process_substs_on_one_elem): Likewise.
	(gen_mnemonic_setattr): Update for move of string_obstack to a
	field of rtx_reader.
	(mnemonic_htab_callback): Likewise.  Fix formatting.
	(gen_mnemonic_attr): Likewise.
	* gentarget-def.c (def_target_insn): Use rtx_reader_ptr for calls
	to print_c_condition.
	* read-md.c: Include "statistics.h" and "vec.h".
	(string_obstack): Convert this global to field "m_string_obstack"
	of class rtx_reader.
	(ptr_locs): Likewise, as "m_ptr_locs".
	(ptr_loc_obstack): Likewise, as "m_ptr_loc_obstack".
	(joined_conditions): Likewise, as "m_joined_conditions".
	(joined_conditions_obstack): Likewise, as "m_joined_conditions_obstack".
	(md_constants): Likewise, as "m_md_constants".
	(enum_types): Likewise, as "m_enum_types".
	(set_md_ptr_loc): Convert to...
	(rtx_reader::set_md_ptr_loc): ...member function.
	(get_md_ptr_loc): Convert to...
	(rtx_reader::get_md_ptr_loc): ...member function.
	(copy_md_ptr_loc): Convert to...
	(rtx_reader::copy_md_ptr_loc): ...member function.
	(fprint_md_ptr_loc): Convert to...
	(rtx_reader::fprint_md_ptr_loc): ...member function.
	(print_md_ptr_loc): Convert to...
	(rtx_reader::print_md_ptr_loc): ...member function.
	(join_c_conditions): Convert to...
	(rtx_reader::join_c_conditions): ...member function.
	(fprint_c_condition): Convert to...
	(rtx_reader::fprint_c_condition): ...member function.
	(print_c_condition): Convert to...
	(rtx_reader::print_c_condition): ...member function.
	(read_name): Convert to...
	(rtx_reader::read_name): ...member function.
	(read_escape): Convert to...
	(rtx_reader::read_escape): ...member function.
	(read_quoted_string): Convert to...
	(rtx_reader::read_quoted_string): ...member function.
	(read_braced_string): Convert to...
	(rtx_reader::read_braced_string): ...member function.
	(read_string): Convert to...
	(rtx_reader::read_string): ...member function.
	(read_skip_construct): Convert to...
	(rtx_reader::read_skip_construct): ...member function.
	(handle_constants): Convert to...
	(rtx_reader::handle_constants): ...member function.
	(traverse_md_constants): Convert to...
	(rtx_reader::traverse_md_constants): ...member function.
	(handle_enum): Convert to...
	(rtx_reader::handle_enum): ...member function.
	(lookup_enum_type): Convert to...
	(rtx_reader::lookup_enum_type): ...member function.
	(traverse_enum_types): Convert to...
	(rtx_reader::traverse_enum_types): ...member function.
	(rtx_reader::rtx_reader): Move initializations
	of various former global data from rtx_reader::read_md_files to
	here, as fields, along with the call to unlock_std_streams.
	(rtx_reader::~rtx_reader): Clean up m_base_dir, and clean up
	the new fields.
	(rtx_reader::read_md_files): Move initializations of various
	global data from here to the ctor.
	* read-md.h (read_name): Convert to...
	(rtx_reader::read_name): ...member function.
	(rtx_reader::read_escape): New method decl.
	(read_quoted_string): Convert to...
	(rtx_reader::read_quoted_string): ...member function.
	(rtx_reader::read_braced_string): New method decl.
	(read_string): Convert to...
	(rtx_reader::read_string): ...member function.
	(rtx_reader::read_skip_construct): New method decl.
	(rtx_reader::set_md_ptr_loc): New method decl.
	(rtx_reader::get_md_ptr_loc): New method decl.
	(copy_md_ptr_loc): Convert to...
	(rtx_reader::copy_md_ptr_loc): ...member function.
	(fprint_md_ptr_loc): Convert to...
	(rtx_reader::fprint_md_ptr_loc): ...member function.
	(print_md_ptr_loc): Convert to...
	(rtx_reader::print_md_ptr_loc): ...member function.
	(rtx_reader::lookup_enum_type): New method decl.
	(rtx_reader::traverse_enum_types): New method decl.
	(rtx_reader::handle_constants): New method decl.
	(traverse_md_constants): Convert to...
	(rtx_reader::traverse_md_constants): ...member function.
	(rtx_reader::handle_enum): New method decl.
	(rtx_reader::join_c_conditions): New method decl.
	(fprint_c_condition): Convert to...
	(rtx_reader::fprint_c_condition): ...member function.
	(print_c_condition): Convert to...
	(rtx_reader::print_c_condition): ...member function.
	(rtx_reader::apply_iterator_to_string): New method decl.
	(rtx_reader::copy_rtx_for_iterators): New method decl.
	(rtx_reader::read_conditions): New method decl.
	(rtx_reader::record_potential_iterator_use): New method decl.
	(rtx_reader::read_mapping): New method decl.
	(rtx_reader::read_rtx): New method decl.
	(rtx_reader::read_rtx_code): New method decl.
	(rtx_reader::read_rtx_operand): New method decl.
	(rtx_reader::read_nested_rtx): New method decl.
	(rtx_reader::read_rtx_variadic): New method decl.
	(rtx_reader::get_string_obstack): New method.
	(rtx_reader::get_md_constants): New method.
	(string_obstack): Convert global variable decl to...
	(rtx_reader::m_string_obstack): ...this new field.
	(rtx_reader::m_ptr_locs): New field.
	(rtx_reader::m_ptr_loc_obstack): New field.
	(rtx_reader::m_joined_conditions): New field.
	(rtx_reader::m_joined_conditions_obstack): New field.
	(rtx_reader::m_md_constants): New field.
	(rtx_reader::m_enum_types): New field.
	* read-rtl.c (apply_iterator_to_string): Convert to...
	(rtx_reader::apply_iterator_to_string): ...member function.
	(copy_rtx_for_iterators): Convert to...
	(rtx_reader::copy_rtx_for_iterators): ...member function.
	(add_condition_to_string): Use rtx_reader_ptr for
	calls join_c_conditions.
	(apply_iterators): Use rtx_reader_ptr for calls to
	join_c_conditions and copy_rtx_for_iterators.
	(read_conditions): Convert to...
	(rtx_reader::read_conditions): ...member function.
	(record_potential_iterator_use): Convert to...
	(rtx_reader::record_potential_iterator_use): ...member function.
	(read_mapping): Convert to...
	(rtx_reader::read_mapping): ...member function.
	(read_subst_mapping): Use rtx_reader_ptr for read_string call.
	(read_rtx): Convert to...
	(rtx_reader::read_rtx): ...member function.
	(read_rtx_code): Convert to...
	(rtx_reader::read_rtx_code): ...member function.
	(read_rtx_operand): Convert to...
	(rtx_reader::read_rtx_operand): ...member function.  Update for move
	of string_obstack to a field.
	(read_nested_rtx): Convert to..
	(rtx_reader::read_nested_rtx): ...member function.
	(read_rtx_variadic): Convert to..
	(rtx_reader::read_rtx_variadic): ...member function.
---
 gcc/genattrtab.c    |  10 +--
 gcc/genconditions.c |   6 +-
 gcc/genconstants.c  |   6 +-
 gcc/genemit.c       |   2 +-
 gcc/genenums.c      |   4 +-
 gcc/genmddeps.c     |   2 +
 gcc/genoutput.c     |   2 +-
 gcc/genpreds.c      |   4 +-
 gcc/genrecog.c      |   2 +-
 gcc/gensupport.c    |  42 ++++++-----
 gcc/gentarget-def.c |   2 +-
 gcc/read-md.c       | 195 +++++++++++++++++++++++++---------------------------
 gcc/read-md.h       |  76 +++++++++++++++++---
 gcc/read-rtl.c      |  76 ++++++++++----------
 14 files changed, 243 insertions(+), 186 deletions(-)

diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c
index dbcdcfc..ddce135 100644
--- a/gcc/genattrtab.c
+++ b/gcc/genattrtab.c
@@ -630,7 +630,7 @@ attr_string (const char *str, int len)
   memcpy (new_str, str, len);
   new_str[len] = '\0';
   attr_hash_add_string (hashcode, new_str);
-  copy_md_ptr_loc (new_str, str);
+  rtx_reader_ptr->copy_md_ptr_loc (new_str, str);
 
   return new_str;			/* Return the new string.  */
 }
@@ -3157,7 +3157,7 @@ gen_attr (md_rtx_info *info)
   if (GET_CODE (def) == DEFINE_ENUM_ATTR)
     {
       attr->enum_name = XSTR (def, 1);
-      et = lookup_enum_type (XSTR (def, 1));
+      et = rtx_reader_ptr->lookup_enum_type (XSTR (def, 1));
       if (!et || !et->md_p)
 	error_at (info->loc, "No define_enum called `%s' defined",
 		  attr->name);
@@ -3768,14 +3768,14 @@ write_test_expr (FILE *outf, rtx exp, unsigned int attrs_cached, int flags,
       break;
 
     case MATCH_TEST:
-      fprint_c_condition (outf, XSTR (exp, 0));
+      rtx_reader_ptr->fprint_c_condition (outf, XSTR (exp, 0));
       if (flags & FLG_BITWISE)
 	fprintf (outf, " != 0");
       break;
 
     /* A random C expression.  */
     case SYMBOL_REF:
-      fprint_c_condition (outf, XSTR (exp, 0));
+      rtx_reader_ptr->fprint_c_condition (outf, XSTR (exp, 0));
       break;
 
     /* The address of the branch target.  */
@@ -4365,7 +4365,7 @@ write_attr_value (FILE *outf, struct attr_desc *attr, rtx value)
       break;
 
     case SYMBOL_REF:
-      fprint_c_condition (outf, XSTR (value, 0));
+      rtx_reader_ptr->fprint_c_condition (outf, XSTR (value, 0));
       break;
 
     case ATTR:
diff --git a/gcc/genconditions.c b/gcc/genconditions.c
index 923b23c..63e0784 100644
--- a/gcc/genconditions.c
+++ b/gcc/genconditions.c
@@ -124,7 +124,7 @@ write_one_condition (void **slot, void * ARG_UNUSED (dummy))
   const struct c_test *test = * (const struct c_test **) slot;
   const char *p;
 
-  print_md_ptr_loc (test->expr);
+  rtx_reader_ptr->print_md_ptr_loc (test->expr);
   fputs ("  { \"", stdout);
   for (p = test->expr; *p; p++)
     {
@@ -139,9 +139,9 @@ write_one_condition (void **slot, void * ARG_UNUSED (dummy))
     }
 
   fputs ("\",\n    __builtin_constant_p ", stdout);
-  print_c_condition (test->expr);
+  rtx_reader_ptr->print_c_condition (test->expr);
   fputs ("\n    ? (int) ", stdout);
-  print_c_condition (test->expr);
+  rtx_reader_ptr->print_c_condition (test->expr);
   fputs ("\n    : -1 },\n", stdout);
   return 1;
 }
diff --git a/gcc/genconstants.c b/gcc/genconstants.c
index e8be5b6..bfc6d07 100644
--- a/gcc/genconstants.c
+++ b/gcc/genconstants.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "errors.h"
+#include "statistics.h"
+#include "vec.h"
 #include "read-md.h"
 
 /* Called via traverse_md_constants; emit a #define for
@@ -91,8 +93,8 @@ main (int argc, const char **argv)
   puts ("#ifndef GCC_INSN_CONSTANTS_H");
   puts ("#define GCC_INSN_CONSTANTS_H\n");
 
-  traverse_md_constants (print_md_constant, 0);
-  traverse_enum_types (print_enum_type, 0);
+  reader.traverse_md_constants (print_md_constant, 0);
+  reader.traverse_enum_types (print_enum_type, 0);
 
   puts ("\n#endif /* GCC_INSN_CONSTANTS_H */");
 
diff --git a/gcc/genemit.c b/gcc/genemit.c
index fe29895..3cf71c7 100644
--- a/gcc/genemit.c
+++ b/gcc/genemit.c
@@ -302,7 +302,7 @@ emit_c_code (const char *code, bool can_fail_p, const char *name)
   printf ("#define DONE return (_val = get_insns (),"
 	  "end_sequence (), _val)\n");
 
-  print_md_ptr_loc (code);
+  rtx_reader_ptr->print_md_ptr_loc (code);
   printf ("%s\n", code);
 
   printf ("#undef DONE\n");
diff --git a/gcc/genenums.c b/gcc/genenums.c
index 8af8d9a..2dc98ce 100644
--- a/gcc/genenums.c
+++ b/gcc/genenums.c
@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "errors.h"
+#include "statistics.h"
+#include "vec.h"
 #include "read-md.h"
 
 /* Called via traverse_enum_types.  Emit an enum definition for
@@ -59,7 +61,7 @@ main (int argc, const char **argv)
   puts ("#include \"system.h\"\n");
   puts ("#include \"insn-constants.h\"\n");
 
-  traverse_enum_types (print_enum_type, 0);
+  reader.traverse_enum_types (print_enum_type, 0);
 
   if (ferror (stdout) || fflush (stdout) || fclose (stdout))
     return FATAL_EXIT_CODE;
diff --git a/gcc/genmddeps.c b/gcc/genmddeps.c
index e3d229d..f97020f 100644
--- a/gcc/genmddeps.c
+++ b/gcc/genmddeps.c
@@ -19,6 +19,8 @@
 #include "system.h"
 #include "coretypes.h"
 #include "errors.h"
+#include "statistics.h"
+#include "vec.h"
 #include "read-md.h"
 
 
diff --git a/gcc/genoutput.c b/gcc/genoutput.c
index 9b6dd09..fd36c04 100644
--- a/gcc/genoutput.c
+++ b/gcc/genoutput.c
@@ -631,7 +631,7 @@ process_template (struct data *d, const char *template_code)
       printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx_insn *insn ATTRIBUTE_UNUSED)\n",
 	      d->code_number);
       puts ("{");
-      print_md_ptr_loc (template_code);
+      rtx_reader_ptr->print_md_ptr_loc (template_code);
       puts (template_code + 1);
       puts ("}");
     }
diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index 23a7e18..c5d597c 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -154,7 +154,7 @@ write_predicate_subfunction (struct pred_data *p)
   printf ("static inline int\n"
 	  "%s_1 (rtx op, machine_mode mode ATTRIBUTE_UNUSED)\n",
 	  p->name);
-  print_md_ptr_loc (p->c_block);
+  rtx_reader_ptr->print_md_ptr_loc (p->c_block);
   if (p->c_block[0] == '{')
     fputs (p->c_block, stdout);
   else
@@ -538,7 +538,7 @@ write_predicate_expr (rtx exp)
       break;
 
     case MATCH_TEST:
-      print_c_condition (XSTR (exp, 0));
+      rtx_reader_ptr->print_c_condition (XSTR (exp, 0));
       break;
 
     default:
diff --git a/gcc/genrecog.c b/gcc/genrecog.c
index 3e5b0f7..4277a9c 100644
--- a/gcc/genrecog.c
+++ b/gcc/genrecog.c
@@ -4659,7 +4659,7 @@ print_test (output_state *os, const rtx_test &test, bool is_param,
       gcc_assert (!is_param && value == 1);
       if (invert_p)
 	printf ("!");
-      print_c_condition (test.u.string);
+      rtx_reader_ptr->print_c_condition (test.u.string);
       break;
 
     case rtx_test::ACCEPT:
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index cb74aea..c49ad6f 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -551,8 +551,9 @@ process_rtx (rtx desc, file_location loc)
 	split_cond = XSTR (desc, 4);
 	if (split_cond[0] == '&' && split_cond[1] == '&')
 	  {
-	    copy_md_ptr_loc (split_cond + 2, split_cond);
-	    split_cond = join_c_conditions (XSTR (desc, 2), split_cond + 2);
+	    rtx_reader_ptr->copy_md_ptr_loc (split_cond + 2, split_cond);
+	    split_cond = rtx_reader_ptr->join_c_conditions (XSTR (desc, 2),
+							    split_cond + 2);
 	  }
 	XSTR (split, 1) = split_cond;
 	XVEC (split, 2) = XVEC (desc, 5);
@@ -1262,8 +1263,8 @@ static const char *
 alter_test_for_insn (struct queue_elem *ce_elem,
 		     struct queue_elem *insn_elem)
 {
-  return join_c_conditions (XSTR (ce_elem->data, 1),
-			    XSTR (insn_elem->data, 2));
+  return rtx_reader_ptr->join_c_conditions (XSTR (ce_elem->data, 1),
+					    XSTR (insn_elem->data, 2));
 }
 
 /* Modify VAL, which is an attribute expression for the "enabled" attribute,
@@ -1871,8 +1872,9 @@ process_substs_on_one_elem (struct queue_elem *elem,
 
       /* Recalculate condition, joining conditions from original and
 	 DEFINE_SUBST input patterns.  */
-      XSTR (elem->data, 2) = join_c_conditions (XSTR (subst_elem->data, 2),
-						XSTR (elem->data, 2));
+      XSTR (elem->data, 2)
+	= rtx_reader_ptr->join_c_conditions (XSTR (subst_elem->data, 2),
+					     XSTR (elem->data, 2));
       /* Mark that subst was applied by changing attribute from "yes"
 	 to "no".  */
       change_subst_attribute (elem, subst_elem, subst_false);
@@ -2299,6 +2301,7 @@ gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn)
   rtx set_attr;
   char *attr_name;
   rtvec new_vec;
+  struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack ();
 
   template_code = XTMPL (insn, 3);
 
@@ -2324,13 +2327,13 @@ gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn)
 	  sp = ep + 1;
 
       if (i > 0)
-	obstack_1grow (&string_obstack, ',');
+	obstack_1grow (string_obstack, ',');
 
       while (cp < sp && ((*cp >= '0' && *cp <= '9')
 			 || (*cp >= 'a' && *cp <= 'z')))
 
 	{
-	  obstack_1grow (&string_obstack, *cp);
+	  obstack_1grow (string_obstack, *cp);
 	  cp++;
 	  size++;
 	}
@@ -2341,7 +2344,7 @@ gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn)
 	    {
 	      /* Don't set a value if there are more than one
 		 instruction in the string.  */
-	      obstack_blank_fast (&string_obstack, -size);
+	      obstack_blank_fast (string_obstack, -size);
 	      size = 0;
 
 	      cp = sp;
@@ -2350,22 +2353,22 @@ gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn)
 	  cp++;
 	}
       if (size == 0)
-	obstack_1grow (&string_obstack, '*');
+	obstack_1grow (string_obstack, '*');
       else
 	add_mnemonic_string (mnemonic_htab,
-			     (char *) obstack_next_free (&string_obstack) - size,
+			     (char *) obstack_next_free (string_obstack) - size,
 			     size);
       i++;
     }
 
   /* An insn definition might emit an empty string.  */
-  if (obstack_object_size (&string_obstack) == 0)
+  if (obstack_object_size (string_obstack) == 0)
     return;
 
-  obstack_1grow (&string_obstack, '\0');
+  obstack_1grow (string_obstack, '\0');
 
   set_attr = rtx_alloc (SET_ATTR);
-  XSTR (set_attr, 1) = XOBFINISH (&string_obstack, char *);
+  XSTR (set_attr, 1) = XOBFINISH (string_obstack, char *);
   attr_name = XNEWVAR (char, strlen (MNEMONIC_ATTR_NAME) + 1);
   strcpy (attr_name, MNEMONIC_ATTR_NAME);
   XSTR (set_attr, 0) = attr_name;
@@ -2388,8 +2391,10 @@ gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn)
 static int
 mnemonic_htab_callback (void **slot, void *info ATTRIBUTE_UNUSED)
 {
-  obstack_grow (&string_obstack, (char*)*slot, strlen ((char*)*slot));
-  obstack_1grow (&string_obstack, ',');
+  struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack ();
+
+  obstack_grow (string_obstack, (char*) *slot, strlen ((char*) *slot));
+  obstack_1grow (string_obstack, ',');
   return 1;
 }
 
@@ -2407,6 +2412,7 @@ gen_mnemonic_attr (void)
   htab_t mnemonic_htab;
   const char *str, *p;
   int i;
+  struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack ();
 
   if (have_error)
     return;
@@ -2470,8 +2476,8 @@ gen_mnemonic_attr (void)
   htab_traverse (mnemonic_htab, mnemonic_htab_callback, NULL);
 
   /* Replace the last ',' with the zero end character.  */
-  *((char *)obstack_next_free (&string_obstack) - 1) = '\0';
-  XSTR (mnemonic_attr, 1) = XOBFINISH (&string_obstack, char *);
+  *((char *) obstack_next_free (string_obstack) - 1) = '\0';
+  XSTR (mnemonic_attr, 1) = XOBFINISH (string_obstack, char *);
 }
 
 /* Check if there are DEFINE_ATTRs with the same name.  */
diff --git a/gcc/gentarget-def.c b/gcc/gentarget-def.c
index adbb564..cf4b166 100644
--- a/gcc/gentarget-def.c
+++ b/gcc/gentarget-def.c
@@ -191,7 +191,7 @@ def_target_insn (const char *name, const char *prototype)
 	      printf ("target_have_%s (void)\n", name);
 	      printf ("{\n");
 	      printf ("  return ");
-	      print_c_condition (test);
+	      rtx_reader_ptr->print_c_condition (test);
 	      printf (";\n");
 	      printf ("}\n");
 	    }
diff --git a/gcc/read-md.c b/gcc/read-md.c
index e158be5..6fe2600 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "errors.h"
+#include "statistics.h"
+#include "vec.h"
 #include "read-md.h"
 
 /* Associates PTR (which can be a string, etc.) with the file location
@@ -31,25 +33,6 @@ struct ptr_loc {
   int lineno;
 };
 
-/* Obstack used for allocating MD strings.  */
-struct obstack string_obstack;
-
-/* A table of ptr_locs, hashed on the PTR field.  */
-static htab_t ptr_locs;
-
-/* An obstack for the above.  Plain xmalloc is a bit heavyweight for a
-   small structure like ptr_loc.  */
-static struct obstack ptr_loc_obstack;
-
-/* A hash table of triples (A, B, C), where each of A, B and C is a condition
-   and A is equivalent to "B && C".  This is used to keep track of the source
-   of conditions that are made up of separate MD strings (such as the split
-   condition of a define_insn_and_split).  */
-static htab_t joined_conditions;
-
-/* An obstack for allocating joined_conditions entries.  */
-static struct obstack joined_conditions_obstack;
-
 /* This callback will be invoked whenever an md include directive is
    processed.  To be used for creation of the dependency file.  */
 void (*include_callback) (const char *);
@@ -58,13 +41,6 @@ void (*include_callback) (const char *);
 
 rtx_reader *rtx_reader_ptr;
 
-/* A table of md_constant structures, hashed by name.  Null if no
-   constant expansion should occur.  */
-static htab_t md_constants;
-
-/* A table of enum_type structures, hashed by name.  */
-static htab_t enum_types;
-
 /* Given an object that starts with a char * name field, return a hash
    code for its name.  */
 
@@ -102,32 +78,32 @@ leading_ptr_eq_p (const void *def1, const void *def2)
 
 /* Associate PTR with the file position given by FILENAME and LINENO.  */
 
-static void
-set_md_ptr_loc (const void *ptr, const char *filename, int lineno)
+void
+rtx_reader::set_md_ptr_loc (const void *ptr, const char *filename, int lineno)
 {
   struct ptr_loc *loc;
 
-  loc = (struct ptr_loc *) obstack_alloc (&ptr_loc_obstack,
+  loc = (struct ptr_loc *) obstack_alloc (&m_ptr_loc_obstack,
 					  sizeof (struct ptr_loc));
   loc->ptr = ptr;
   loc->filename = filename;
   loc->lineno = lineno;
-  *htab_find_slot (ptr_locs, loc, INSERT) = loc;
+  *htab_find_slot (m_ptr_locs, loc, INSERT) = loc;
 }
 
 /* Return the position associated with pointer PTR.  Return null if no
    position was set.  */
 
-static const struct ptr_loc *
-get_md_ptr_loc (const void *ptr)
+const struct ptr_loc *
+rtx_reader::get_md_ptr_loc (const void *ptr)
 {
-  return (const struct ptr_loc *) htab_find (ptr_locs, &ptr);
+  return (const struct ptr_loc *) htab_find (m_ptr_locs, &ptr);
 }
 
 /* Associate NEW_PTR with the same file position as OLD_PTR.  */
 
 void
-copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
+rtx_reader::copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
 {
   const struct ptr_loc *loc = get_md_ptr_loc (old_ptr);
   if (loc != 0)
@@ -138,7 +114,7 @@ copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
    directive for it to OUTF.  */
 
 void
-fprint_md_ptr_loc (FILE *outf, const void *ptr)
+rtx_reader::fprint_md_ptr_loc (FILE *outf, const void *ptr)
 {
   const struct ptr_loc *loc = get_md_ptr_loc (ptr);
   if (loc != 0)
@@ -147,7 +123,7 @@ fprint_md_ptr_loc (FILE *outf, const void *ptr)
 
 /* Special fprint_md_ptr_loc for writing to STDOUT.  */
 void
-print_md_ptr_loc (const void *ptr)
+rtx_reader::print_md_ptr_loc (const void *ptr)
 {
   fprint_md_ptr_loc (stdout, ptr);
 }
@@ -156,7 +132,7 @@ print_md_ptr_loc (const void *ptr)
    may be null or empty.  */
 
 const char *
-join_c_conditions (const char *cond1, const char *cond2)
+rtx_reader::join_c_conditions (const char *cond1, const char *cond2)
 {
   char *result;
   const void **entry;
@@ -171,11 +147,11 @@ join_c_conditions (const char *cond1, const char *cond2)
     return cond1;
 
   result = concat ("(", cond1, ") && (", cond2, ")", NULL);
-  obstack_ptr_grow (&joined_conditions_obstack, result);
-  obstack_ptr_grow (&joined_conditions_obstack, cond1);
-  obstack_ptr_grow (&joined_conditions_obstack, cond2);
-  entry = XOBFINISH (&joined_conditions_obstack, const void **);
-  *htab_find_slot (joined_conditions, entry, INSERT) = entry;
+  obstack_ptr_grow (&m_joined_conditions_obstack, result);
+  obstack_ptr_grow (&m_joined_conditions_obstack, cond1);
+  obstack_ptr_grow (&m_joined_conditions_obstack, cond2);
+  entry = XOBFINISH (&m_joined_conditions_obstack, const void **);
+  *htab_find_slot (m_joined_conditions, entry, INSERT) = entry;
   return result;
 }
 
@@ -185,9 +161,9 @@ join_c_conditions (const char *cond1, const char *cond2)
    directive for COND if its original file position is known.  */
 
 void
-fprint_c_condition (FILE *outf, const char *cond)
+rtx_reader::fprint_c_condition (FILE *outf, const char *cond)
 {
-  const char **halves = (const char **) htab_find (joined_conditions, &cond);
+  const char **halves = (const char **) htab_find (m_joined_conditions, &cond);
   if (halves != 0)
     {
       fprintf (outf, "(");
@@ -207,7 +183,7 @@ fprint_c_condition (FILE *outf, const char *cond)
 /* Special fprint_c_condition for writing to STDOUT.  */
 
 void
-print_c_condition (const char *cond)
+rtx_reader::print_c_condition (const char *cond)
 {
   fprint_c_condition (stdout, cond);
 }
@@ -414,7 +390,7 @@ rtx_reader::unread_char (int ch)
    punctuation chars of rtx printed syntax.  */
 
 void
-read_name (struct md_name *name)
+rtx_reader::read_name (struct md_name *name)
 {
   int c;
   size_t i;
@@ -458,7 +434,7 @@ read_name (struct md_name *name)
   name->buffer[i] = 0;
   name->string = name->buffer;
 
-  if (md_constants)
+  if (m_md_constants)
     {
       /* Do constant expansion.  */
       struct md_constant *def;
@@ -468,7 +444,7 @@ read_name (struct md_name *name)
 	  struct md_constant tmp_def;
 
 	  tmp_def.name = name->string;
-	  def = (struct md_constant *) htab_find (md_constants, &tmp_def);
+	  def = (struct md_constant *) htab_find (m_md_constants, &tmp_def);
 	  if (def)
 	    name->string = def->value;
 	}
@@ -479,8 +455,8 @@ read_name (struct md_name *name)
 /* Subroutine of the string readers.  Handles backslash escapes.
    Caller has read the backslash, but not placed it into the obstack.  */
 
-static void
-read_escape (void)
+void
+rtx_reader::read_escape ()
 {
   int c = read_char ();
 
@@ -508,32 +484,32 @@ read_escape (void)
     case 'a': case 'b': case 'f': case 'n': case 'r': case 't': case 'v':
     case '0': case '1': case '2': case '3': case '4': case '5': case '6':
     case '7': case 'x':
-      obstack_1grow (&string_obstack, '\\');
+      obstack_1grow (&m_string_obstack, '\\');
       break;
 
       /* \; makes stuff for a C string constant containing
 	 newline and tab.  */
     case ';':
-      obstack_grow (&string_obstack, "\\n\\t", 4);
+      obstack_grow (&m_string_obstack, "\\n\\t", 4);
       return;
 
       /* pass anything else through, but issue a warning.  */
     default:
       fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
-	       rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+	       get_filename (), get_lineno (),
 	       c);
-      obstack_1grow (&string_obstack, '\\');
+      obstack_1grow (&m_string_obstack, '\\');
       break;
     }
 
-  obstack_1grow (&string_obstack, c);
+  obstack_1grow (&m_string_obstack, c);
 }
 
 /* Read a double-quoted string onto the obstack.  Caller has scanned
    the leading quote.  */
 
 char *
-read_quoted_string (void)
+rtx_reader::read_quoted_string ()
 {
   int c;
 
@@ -548,25 +524,25 @@ read_quoted_string (void)
       else if (c == '"' || c == EOF)
 	break;
 
-      obstack_1grow (&string_obstack, c);
+      obstack_1grow (&m_string_obstack, c);
     }
 
-  obstack_1grow (&string_obstack, 0);
-  return XOBFINISH (&string_obstack, char *);
+  obstack_1grow (&m_string_obstack, 0);
+  return XOBFINISH (&m_string_obstack, char *);
 }
 
 /* Read a braced string (a la Tcl) onto the string obstack.  Caller
    has scanned the leading brace.  Note that unlike quoted strings,
    the outermost braces _are_ included in the string constant.  */
 
-static char *
-read_braced_string (void)
+char *
+rtx_reader::read_braced_string ()
 {
   int c;
   int brace_depth = 1;  /* caller-processed */
-  unsigned long starting_read_md_lineno = rtx_reader_ptr->get_lineno ();
+  unsigned long starting_read_md_lineno = get_lineno ();
 
-  obstack_1grow (&string_obstack, '{');
+  obstack_1grow (&m_string_obstack, '{');
   while (brace_depth)
     {
       c = read_char (); /* Read the string  */
@@ -585,11 +561,11 @@ read_braced_string (void)
 	  ("missing closing } for opening brace on line %lu",
 	   starting_read_md_lineno);
 
-      obstack_1grow (&string_obstack, c);
+      obstack_1grow (&m_string_obstack, c);
     }
 
-  obstack_1grow (&string_obstack, 0);
-  return XOBFINISH (&string_obstack, char *);
+  obstack_1grow (&m_string_obstack, 0);
+  return XOBFINISH (&m_string_obstack, char *);
 }
 
 /* Read some kind of string constant.  This is the high-level routine
@@ -597,7 +573,7 @@ read_braced_string (void)
    and dispatch to the appropriate string constant reader.  */
 
 char *
-read_string (int star_if_braced)
+rtx_reader::read_string (int star_if_braced)
 {
   char *stringbuf;
   int saw_paren = 0;
@@ -610,13 +586,13 @@ read_string (int star_if_braced)
       c = read_skip_spaces ();
     }
 
-  old_lineno = rtx_reader_ptr->get_lineno ();
+  old_lineno = get_lineno ();
   if (c == '"')
     stringbuf = read_quoted_string ();
   else if (c == '{')
     {
       if (star_if_braced)
-	obstack_1grow (&string_obstack, '*');
+	obstack_1grow (&m_string_obstack, '*');
       stringbuf = read_braced_string ();
     }
   else
@@ -625,15 +601,15 @@ read_string (int star_if_braced)
   if (saw_paren)
     require_char_ws (')');
 
-  set_md_ptr_loc (stringbuf, rtx_reader_ptr->get_filename (), old_lineno);
+  set_md_ptr_loc (stringbuf, get_filename (), old_lineno);
   return stringbuf;
 }
 
 /* Skip the rest of a construct that started at line LINENO and that
    is currently nested by DEPTH levels of parentheses.  */
 
-static void
-read_skip_construct (int depth, file_location loc)
+void
+rtx_reader::read_skip_construct (int depth, file_location loc)
 {
   struct md_name name;
   int c;
@@ -774,8 +750,8 @@ add_constant (htab_t defs, char *name, char *value,
 /* Process a define_constants directive, starting with the optional space
    after the "define_constants".  */
 
-static void
-handle_constants (void)
+void
+rtx_reader::handle_constants ()
 {
   int c;
   htab_t defs;
@@ -783,8 +759,8 @@ handle_constants (void)
   require_char_ws ('[');
 
   /* Disable constant expansion during definition processing.  */
-  defs = md_constants;
-  md_constants = 0;
+  defs = m_md_constants;
+  m_md_constants = 0;
   while ( (c = read_skip_spaces ()) != ']')
     {
       struct md_name name, value;
@@ -798,7 +774,7 @@ handle_constants (void)
 
       require_char_ws (')');
     }
-  md_constants = defs;
+  m_md_constants = defs;
 }
 
 /* For every constant definition, call CALLBACK with two arguments:
@@ -806,9 +782,9 @@ handle_constants (void)
    Stop when CALLBACK returns zero.  */
 
 void
-traverse_md_constants (htab_trav callback, void *info)
+rtx_reader::traverse_md_constants (htab_trav callback, void *info)
 {
-  htab_traverse (md_constants, callback, info);
+  htab_traverse (get_md_constants (), callback, info);
 }
 
 /* Return a malloc()ed decimal string that represents number NUMBER.  */
@@ -828,8 +804,8 @@ md_decimal_string (int number)
    number on which the directive started and MD_P is true if the
    directive is a define_enum rather than a define_c_enum.  */
 
-static void
-handle_enum (file_location loc, bool md_p)
+void
+rtx_reader::handle_enum (file_location loc, bool md_p)
 {
   char *enum_name, *value_name;
   struct md_name name;
@@ -839,7 +815,7 @@ handle_enum (file_location loc, bool md_p)
   int c;
 
   enum_name = read_string (false);
-  slot = htab_find_slot (enum_types, &enum_name, INSERT);
+  slot = htab_find_slot (m_enum_types, &enum_name, INSERT);
   if (*slot)
     {
       def = (struct enum_type *) *slot;
@@ -883,7 +859,7 @@ handle_enum (file_location loc, bool md_p)
 	  value_name = xstrdup (name.string);
 	  ev->name = value_name;
 	}
-      ev->def = add_constant (md_constants, value_name,
+      ev->def = add_constant (get_md_constants (), value_name,
 			      md_decimal_string (def->num_values), def);
 
       *def->tail_ptr = ev;
@@ -895,9 +871,9 @@ handle_enum (file_location loc, bool md_p)
 /* Try to find the definition of the given enum.  Return null on failure.  */
 
 struct enum_type *
-lookup_enum_type (const char *name)
+rtx_reader::lookup_enum_type (const char *name)
 {
-  return (struct enum_type *) htab_find (enum_types, &name);
+  return (struct enum_type *) htab_find (m_enum_types, &name);
 }
 
 /* For every enum definition, call CALLBACK with two arguments:
@@ -905,9 +881,9 @@ lookup_enum_type (const char *name)
    returns zero.  */
 
 void
-traverse_enum_types (htab_trav callback, void *info)
+rtx_reader::traverse_enum_types (htab_trav callback, void *info)
 {
-  htab_traverse (enum_types, callback, info);
+  htab_traverse (m_enum_types, callback, info);
 }
 
 
@@ -925,12 +901,43 @@ rtx_reader::rtx_reader ()
 {
   /* Set the global singleton pointer.  */
   rtx_reader_ptr = this;
+
+  obstack_init (&m_string_obstack);
+
+  m_ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
+  obstack_init (&m_ptr_loc_obstack);
+
+  m_joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
+  obstack_init (&m_joined_conditions_obstack);
+
+  m_md_constants = htab_create (31, leading_string_hash,
+				leading_string_eq_p, (htab_del) 0);
+
+  m_enum_types = htab_create (31, leading_string_hash,
+			      leading_string_eq_p, (htab_del) 0);
+
+  /* Unlock the stdio streams.  */
+  unlock_std_streams ();
 }
 
 /* rtx_reader's destructor.  */
 
 rtx_reader::~rtx_reader ()
 {
+  free (m_base_dir);
+
+  htab_delete (m_enum_types);
+
+  htab_delete (m_md_constants);
+
+  obstack_free (&m_joined_conditions_obstack, NULL);
+  htab_delete (m_joined_conditions);
+
+  obstack_free (&m_ptr_loc_obstack, NULL);
+  htab_delete (m_ptr_locs);
+
+  obstack_free (&m_string_obstack, NULL);
+
   /* Clear the global singleton pointer.  */
   rtx_reader_ptr = NULL;
 }
@@ -1105,20 +1112,6 @@ rtx_reader::read_md_files (int argc, const char **argv,
   bool already_read_stdin;
   int num_files;
 
-  /* Initialize global data.  */
-  obstack_init (&string_obstack);
-  ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
-  obstack_init (&ptr_loc_obstack);
-  joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
-  obstack_init (&joined_conditions_obstack);
-  md_constants = htab_create (31, leading_string_hash,
-			      leading_string_eq_p, (htab_del) 0);
-  enum_types = htab_create (31, leading_string_hash,
-			    leading_string_eq_p, (htab_del) 0);
-
-  /* Unlock the stdio streams.  */
-  unlock_std_streams ();
-
   /* First we loop over all the options.  */
   for (i = 1; i < argc; i++)
     if (argv[i][0] == '-')
diff --git a/gcc/read-md.h b/gcc/read-md.h
index a74cc72..996b514 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -107,14 +107,54 @@ class rtx_reader
 
   file_location get_current_location () const;
 
+  /* Defined in read-md.c.  */
   int read_char (void);
   void unread_char (int ch);
+  void read_name (struct md_name *name);
+  void read_escape ();
+  char *read_quoted_string ();
+  char *read_braced_string ();
+  char *read_string (int star_if_braced);
+  void read_skip_construct (int depth, file_location loc);
+
+  void set_md_ptr_loc (const void *ptr, const char *filename, int lineno);
+  const struct ptr_loc *get_md_ptr_loc (const void *ptr);
+  void copy_md_ptr_loc (const void *new_ptr, const void *old_ptr);
+  void fprint_md_ptr_loc (FILE *outf, const void *ptr);
+  void print_md_ptr_loc (const void *ptr);
+
+  struct enum_type *lookup_enum_type (const char *name);
+  void traverse_enum_types (htab_trav callback, void *info);
+
+  void handle_constants ();
+  void traverse_md_constants (htab_trav callback, void *info);
+  void handle_enum (file_location loc, bool md_p);
+
+  const char *join_c_conditions (const char *cond1, const char *cond2);
+  void fprint_c_condition (FILE *outf, const char *cond);
+  void print_c_condition (const char *cond);
+
+  /* Defined in read-rtl.c.  */
+  const char *apply_iterator_to_string (const char *string);
+  rtx copy_rtx_for_iterators (rtx original);
+  void read_conditions ();
+  void record_potential_iterator_use (struct iterator_group *group,
+				      void *ptr, const char *name);
+  struct mapping *read_mapping (struct iterator_group *group, htab_t table);
+  bool read_rtx (const char *rtx_name, vec<rtx> *rtxen);
+  rtx read_rtx_code (const char *code_name);
+  void read_rtx_operand (rtx return_rtx, int idx);
+  rtx read_nested_rtx ();
+  rtx read_rtx_variadic (rtx form);
 
   const char *get_top_level_filename () const { return m_toplevel_fname; }
   const char *get_filename () const { return m_read_md_filename; }
   int get_lineno () const { return m_read_md_lineno; }
   int get_colno () const { return m_read_md_colno; }
 
+  struct obstack *get_string_obstack () { return &m_string_obstack; }
+  htab_t get_md_constants () { return m_md_constants; }
+
  private:
   /* A singly-linked list of filenames.  */
   struct file_name_list {
@@ -159,6 +199,32 @@ class rtx_reader
 
   /* A pointer to the null terminator of the md include chain.  */
   file_name_list **m_last_dir_md_include_ptr;
+
+  /* Obstack used for allocating MD strings.  */
+  struct obstack m_string_obstack;
+
+  /* A table of ptr_locs, hashed on the PTR field.  */
+  htab_t m_ptr_locs;
+
+  /* An obstack for the above.  Plain xmalloc is a bit heavyweight for a
+     small structure like ptr_loc.  */
+  struct obstack m_ptr_loc_obstack;
+
+  /* A hash table of triples (A, B, C), where each of A, B and C is a condition
+     and A is equivalent to "B && C".  This is used to keep track of the source
+     of conditions that are made up of separate MD strings (such as the split
+     condition of a define_insn_and_split).  */
+  htab_t m_joined_conditions;
+
+  /* An obstack for allocating joined_conditions entries.  */
+  struct obstack m_joined_conditions_obstack;
+
+  /* A table of md_constant structures, hashed by name.  Null if no
+     constant expansion should occur.  */
+  htab_t m_md_constants;
+
+  /* A table of enum_type structures, hashed by name.  */
+  htab_t m_enum_types;
 };
 
 /* Global singleton.  */
@@ -175,7 +241,6 @@ class noop_reader : public rtx_reader
   void handle_unknown_directive (file_location, const char *);
 };
 
-extern struct obstack string_obstack;
 extern void (*include_callback) (const char *);
 
 /* Read the next character from the MD file.  */
@@ -196,12 +261,7 @@ unread_char (int ch)
 
 extern hashval_t leading_string_hash (const void *);
 extern int leading_string_eq_p (const void *, const void *);
-extern void copy_md_ptr_loc (const void *, const void *);
-extern void print_md_ptr_loc (const void *);
-extern void fprint_md_ptr_loc (FILE *, const void *);
 extern const char *join_c_conditions (const char *, const char *);
-extern void print_c_condition (const char *);
-extern void fprint_c_condition (FILE *, const char *);
 extern void message_at (file_location, const char *, ...) ATTRIBUTE_PRINTF_2;
 extern void error_at (file_location, const char *, ...) ATTRIBUTE_PRINTF_2;
 extern void fatal_at (file_location, const char *, ...) ATTRIBUTE_PRINTF_2;
@@ -210,13 +270,9 @@ extern void fatal_with_file_and_line (const char *, ...)
 extern void fatal_expected_char (int, int) ATTRIBUTE_NORETURN;
 extern int read_skip_spaces (void);
 extern void require_char_ws (char expected);
-extern void read_name (struct md_name *);
-extern char *read_quoted_string (void);
-extern char *read_string (int);
 extern int n_comma_elts (const char *);
 extern const char *scan_comma_elt (const char **);
 extern void upcase_string (char *);
-extern void traverse_md_constants (htab_trav, void *);
 extern void traverse_enum_types (htab_trav, void *);
 extern struct enum_type *lookup_enum_type (const char *);
 
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 925ea45..7a2021a 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -106,10 +106,6 @@ htab_t subst_attr_to_iter_map = NULL;
 const char *current_iterator_name;
 
 static void validate_const_int (const char *);
-static rtx read_rtx_code (const char *);
-static void read_rtx_operand (rtx, int);
-static rtx read_nested_rtx (void);
-static rtx read_rtx_variadic (rtx);
 
 /* The mode and code iterator structures.  */
 static struct iterator_group modes, codes, ints, substs;
@@ -329,8 +325,8 @@ map_attr_string (const char *p)
 /* Apply the current iterator values to STRING.  Return the new string
    if any changes were needed, otherwise return STRING itself.  */
 
-static const char *
-apply_iterator_to_string (const char *string)
+const char *
+rtx_reader::apply_iterator_to_string (const char *string)
 {
   char *base, *copy, *p, *start, *end;
   struct map_value *v;
@@ -351,14 +347,14 @@ apply_iterator_to_string (const char *string)
 
       /* Add everything between the last copied byte and the '<',
 	 then add in the attribute value.  */
-      obstack_grow (&string_obstack, base, start - base);
-      obstack_grow (&string_obstack, v->string, strlen (v->string));
+      obstack_grow (&m_string_obstack, base, start - base);
+      obstack_grow (&m_string_obstack, v->string, strlen (v->string));
       base = end + 1;
     }
   if (base != copy)
     {
-      obstack_grow (&string_obstack, base, strlen (base) + 1);
-      copy = XOBFINISH (&string_obstack, char *);
+      obstack_grow (&m_string_obstack, base, strlen (base) + 1);
+      copy = XOBFINISH (&m_string_obstack, char *);
       copy_md_ptr_loc (copy, string);
       return copy;
     }
@@ -368,8 +364,8 @@ apply_iterator_to_string (const char *string)
 /* Return a deep copy of X, substituting the current iterator
    values into any strings.  */
 
-static rtx
-copy_rtx_for_iterators (rtx original)
+rtx
+rtx_reader::copy_rtx_for_iterators (rtx original)
 {
   const char *format_ptr, *p;
   int i, j;
@@ -428,7 +424,7 @@ add_condition_to_string (const char *original, const char *extra)
 {
   if (original != 0 && original[0] == '&' && original[1] == '&')
     return original;
-  return join_c_conditions (original, extra);
+  return rtx_reader_ptr->join_c_conditions (original, extra);
 }
 
 /* Like add_condition, but applied to all conditions in rtx X.  */
@@ -543,10 +539,10 @@ apply_iterators (rtx original, vec<rtx> *queue)
 	    continue;
 	  v = iuse->iterator->current_value;
 	  iuse->iterator->group->apply_iterator (iuse->ptr, v->number);
-	  condition = join_c_conditions (condition, v->string);
+	  condition = rtx_reader_ptr->join_c_conditions (condition, v->string);
 	}
       apply_attribute_uses ();
-      x = copy_rtx_for_iterators (original);
+      x = rtx_reader_ptr->copy_rtx_for_iterators (original);
       add_condition_to_rtx (x, condition);
 
       /* We apply subst iterator after RTL-template is copied, as during
@@ -738,8 +734,8 @@ atoll (const char *p)
    generated by (the program generated by) genconditions.c, and
    slipped in at the beginning of the sequence of MD files read by
    most of the other generators.  */
-static void
-read_conditions (void)
+void
+rtx_reader::read_conditions ()
 {
   int c;
 
@@ -837,9 +833,9 @@ record_attribute_use (struct iterator_group *group, void *ptr,
    for group GROUP.  PTR is the value to pass to GROUP's apply_iterator
    callback.  */
 
-static void
-record_potential_iterator_use (struct iterator_group *group, void *ptr,
-			       const char *name)
+void
+rtx_reader::record_potential_iterator_use (struct iterator_group *group,
+					   void *ptr, const char *name)
 {
   struct mapping *m;
   size_t len;
@@ -849,8 +845,8 @@ record_potential_iterator_use (struct iterator_group *group, void *ptr,
     {
       /* Copy the attribute string into permanent storage, without the
 	 angle brackets around it.  */
-      obstack_grow0 (&string_obstack, name + 1, len - 2);
-      record_attribute_use (group, ptr, XOBFINISH (&string_obstack, char *));
+      obstack_grow0 (&m_string_obstack, name + 1, len - 2);
+      record_attribute_use (group, ptr, XOBFINISH (&m_string_obstack, char *));
     }
   else
     {
@@ -872,8 +868,8 @@ record_potential_iterator_use (struct iterator_group *group, void *ptr,
    Represent the declaration as a "mapping" structure; add it to TABLE
    (which belongs to GROUP) and return it.  */
 
-static struct mapping *
-read_mapping (struct iterator_group *group, htab_t table)
+struct mapping *
+rtx_reader::read_mapping (struct iterator_group *group, htab_t table)
 {
   struct md_name name;
   struct mapping *m;
@@ -974,7 +970,7 @@ read_subst_mapping (htab_t subst_iters_table, htab_t subst_attrs_table,
   int i;
 
   for (i = 0; i < 4; i++)
-    attr_operands[i] = read_string (false);
+    attr_operands[i] = rtx_reader_ptr->read_string (false);
 
   add_define_subst_attr (attr_operands, queue);
 
@@ -1019,7 +1015,7 @@ check_code_iterator (struct mapping *iterator)
    store the list of rtxes as an EXPR_LIST in *X.  */
 
 bool
-read_rtx (const char *rtx_name, vec<rtx> *rtxen)
+rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
 {
   static bool initialized = false;
 
@@ -1087,8 +1083,8 @@ read_rtx (const char *rtx_name, vec<rtx> *rtxen)
    either an rtx code or a code iterator.  Parse the rest of the rtx and
    return it.  */
 
-static rtx
-read_rtx_code (const char *code_name)
+rtx
+rtx_reader::read_rtx_code (const char *code_name)
 {
   RTX_CODE code;
   struct mapping *iterator;
@@ -1200,8 +1196,8 @@ read_rtx_code (const char *code_name)
    based on the corresponding format character within GET_RTX_FORMAT
    for the GET_CODE (RETURN_RTX).  */
 
-static void
-read_rtx_operand (rtx return_rtx, int idx)
+void
+rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
 {
   RTX_CODE code = GET_CODE (return_rtx);
   const char *format_ptr = GET_RTX_FORMAT (code);
@@ -1304,17 +1300,17 @@ read_rtx_operand (rtx return_rtx, int idx)
 		|| GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
 	  {
 	    char line_name[20];
-	    const char *read_md_filename = rtx_reader_ptr->get_filename ();
+	    const char *read_md_filename = get_filename ();
 	    const char *fn = (read_md_filename ? read_md_filename : "rtx");
 	    const char *slash;
 	    for (slash = fn; *slash; slash ++)
 	      if (*slash == '/' || *slash == '\\' || *slash == ':')
 		fn = slash + 1;
-	    obstack_1grow (&string_obstack, '*');
-	    obstack_grow (&string_obstack, fn, strlen (fn));
-	    sprintf (line_name, ":%d", rtx_reader_ptr->get_lineno ());
-	    obstack_grow (&string_obstack, line_name, strlen (line_name)+1);
-	    stringbuf = XOBFINISH (&string_obstack, char *);
+	    obstack_1grow (&m_string_obstack, '*');
+	    obstack_grow (&m_string_obstack, fn, strlen (fn));
+	    sprintf (line_name, ":%d", get_lineno ());
+	    obstack_grow (&m_string_obstack, line_name, strlen (line_name)+1);
+	    stringbuf = XOBFINISH (&m_string_obstack, char *);
 	  }
 
 	/* Find attr-names in the string.  */
@@ -1402,8 +1398,8 @@ read_rtx_operand (rtx return_rtx, int idx)
 
 /* Read a nested rtx construct from the MD file and return it.  */
 
-static rtx
-read_nested_rtx (void)
+rtx
+rtx_reader::read_nested_rtx ()
 {
   struct md_name name;
   rtx return_rtx;
@@ -1427,8 +1423,8 @@ read_nested_rtx (void)
    When called, FORM is (thing x1 x2), and the file position
    is just past the leading parenthesis of x3.  Only works
    for THINGs which are dyadic expressions, e.g. AND, IOR.  */
-static rtx
-read_rtx_variadic (rtx form)
+rtx
+rtx_reader::read_rtx_variadic (rtx form)
 {
   char c = '(';
   rtx p = form, q;
-- 
1.8.5.3

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

* Re: [PATCH] read-md.c: Move various state to within class rtx_reader (v3)
  2016-10-17 16:27             ` [PATCH] read-md.c: Move various state to within class rtx_reader (v3) David Malcolm
@ 2016-10-17 20:23               ` Richard Sandiford
  0 siblings, 0 replies; 96+ messages in thread
From: Richard Sandiford @ 2016-10-17 20:23 UTC (permalink / raw)
  To: David Malcolm; +Cc: Bernd Schmidt, gcc-patches

David Malcolm <dmalcolm@redhat.com> writes:
>> I assume you didn't turn the functions above into member functions
>> because they aren't primitives.  OTOH it might seem inconsistent
>> to have things like traverse_enum_types as member functions but
>> traverse_md_constants not.
>
> In the following I've converted traverse_md_constants to a member
> function.
>
> Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.
>
> OK for trunk?

OK, thanks.  And thanks for doing this -- nice clean-up!

Richard

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

* Re: [PATCH 09/16] Split class rtx_reader into base_rtx_reader vs rtx_reader
  2016-10-11 15:53   ` Bernd Schmidt
@ 2016-10-18 20:30     ` David Malcolm
  2016-10-19 14:45       ` Bernd Schmidt
  0 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-18 20:30 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: Richard Sandiford

[CCing Richard; this is re:
  https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00273.html
]

Essentially I want to split class rtx_reader into two parts: a base class covering the things implemented in read-md.o, and a subclass implemented in read-rtl.o.

The motivation is that I want to make some of the rtx-reading functions  in read-rtl.c virtual in a followup, so that they can be overridden by the function_reader subclass in my RTL frontend.  Hence the ctor needs access to these functions in order to access the vtable - or the link fails.

It appears that I can't simply use read-rtl.o everywhere due to 
read-rtl.c needing insn-constants.h, which is built by genconstants, which would be a circular dependency, hence the split between BUILD_MD vs BUILD_RTL in Makefile.in to break this cycle.

On Tue, 2016-10-11 at 17:53 +0200, Bernd Schmidt wrote:
> On 10/05/2016 06:15 PM, David Malcolm wrote:
> > -	  rtx_reader_ptr->get_top_level_filename ());
> > +	  base_rtx_reader_ptr->get_top_level_filename ());
> 
> I wonder if the number of changes could be minimized by retaining the
> name rtx_reader for the base class, and using something more specific
> for the derived ones. Or would that require renaming a bunch of other
> locations?

The number of changes got rather larger with r241293
("[PATCH] read-md.c: Move various state to within class rtx_reader
(v3)"; https://gcc.gnu.org/ml/gcc-patches/2016-10/msg01323.html
), so I'd rather just "bite the bullet" and do the renamings.

I'm not in love with the names I chose in this patch.  It does seem odd
having an "rtx_reader" class that can't actually read hierarchical rtx.

How about "md_reader" as the base class (with responsibility for the
things in read-md.o), and "rtx_reader" for the subclass (adding the
things in read-rtl.o)?

> > -static void
> > -read_rtx_operand (rtx return_rtx, int idx)
> > +rtx
> > +rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
> >  {
> >    RTX_CODE code = GET_CODE (return_rtx);
> >    const char *format_ptr = GET_RTX_FORMAT (code);
> 
>  > +
>  > +  return return_rtx;
>  >  }
>  >
> 
> This appears to be an unrelated change. The return value needs to be 
> documented.

Indeed.  I'll split that change out into a followup.

Thanks
Dave

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

* Re: RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-07 13:58           ` Bernd Schmidt
                               ` (2 preceding siblings ...)
  2016-10-12 17:17             ` [PATCH] Add a "compact" mode to print_rtx_function David Malcolm
@ 2016-10-19 14:36             ` David Malcolm
  2016-10-19 14:42               ` Bernd Schmidt
  3 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-19 14:36 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches

On Fri, 2016-10-07 at 15:58 +0200, Bernd Schmidt wrote:
> On 10/07/2016 03:26 PM, David Malcolm wrote:
> > 
> > We could simply print the INSN_UID for CODE_LABELs; something like
> > this
> > (see the "(code_label 16" below):
> 
> I think that should work.
> 
> > You appear to have trimmed the idea of enclosing the insns with
> > (basic-block) directives without commenting on it.  Did you like
> > this
> > idea?
> 
> Sorry - I appear to have completely missed it.
> 
> > It would make the above look like:
> > 
> >   (basic-block 2
> >     ;; insns snipped
> >     (jump_insn (set (pc)
> >             (if_then_else (ge (reg:CCGC 17 flags)
> >                     (const_int 0 [0]))
> >                 (label_ref 16)
> >                 (pc))) "test.c":3
> >    -> 16)
> >   ) ;; basic-block 2
> >   (basic-block 4
> >     (note [bb 4] NOTE_INSN_BASIC_BLOCK)
> >     ;; insns snipped
> >     (jump_insn (set (pc) (label_ref 20)) "test.c":4
> >      -> 20)
> >   ) ;; basic-block 4
> >   (barrier)
> >   (basic-block 5
> >     (code_label 16 [1 uses])
> >     (note [bb 5] NOTE_INSN_BASIC_BLOCK)
> >     ;; etc
> >   ) ;; basic-block 5
> > 
> > Note how the above format expresses clearly that:
> > * the (barrier) is part of the insn chain, but not in a basic
> > block, and
> > * some insns can happen in a basic block
> 
> That looks really nice IMO. Except maybe drop the "-> 16" bit for the
> jump_insn (that's the JUMP_LABEL, isn't it?)

In r241120 I dropped all dumping of the JUMP_LABEL when adding the
"compact" mode.

I'm now running into an issue with this as I update the __RTL in cc1
tests to use the new format, since various passes require the
JUMP_INSNs to have JUMP_LABEL data.

For reference the JUMP_LABEL is at idx 7 of JUMP_INSN, a code '0' field, it's dumped by a special-case in print-rtx.c:print_rtx_operand_code_0, around line 186:
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/print-rtl.c;hb=HEAD#l186

OK if I simply reinstate the existing dump form for that in compact mode, or would you prefer a different syntax?

Maybe even just lose the newline in compact mode, giving something like the following:

Example of a jump with JUMP_LABEL == a LABEL_REF.

      (cjump_insn (set (pc)
                    (if_then_else (ge (reg:CCGC flags)
                            (const_int 0))
                        (label_ref 16)
                        (pc)))                  (nil) -> 16)


Example of a jump with JUMP_LABEL == the simple_return_rtx singleton.

      (cjump_insn (set (pc) (label_ref 3)) (nil) -> simple_return)

[...snip...]

Dave

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

* Re: RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-19 14:36             ` RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader) David Malcolm
@ 2016-10-19 14:42               ` Bernd Schmidt
  2016-10-19 17:19                 ` David Malcolm
  0 siblings, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-19 14:42 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/19/2016 04:35 PM, David Malcolm wrote:

> In r241120 I dropped all dumping of the JUMP_LABEL when adding the
> "compact" mode.
>
> I'm now running into an issue with this as I update the __RTL in cc1
> tests to use the new format, since various passes require the
> JUMP_INSNs to have JUMP_LABEL data.

Isn't it possible to recreate these? In jump.c we have 
rebuild_jump_labels, which looks like it'll also compute LABEL_NUSES 
which I think we were considering dropping in the output.


Bernd

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

* Re: [PATCH 09/16] Split class rtx_reader into base_rtx_reader vs rtx_reader
  2016-10-18 20:30     ` David Malcolm
@ 2016-10-19 14:45       ` Bernd Schmidt
  2016-10-20 19:14         ` Richard Sandiford
  0 siblings, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-19 14:45 UTC (permalink / raw)
  To: David Malcolm, gcc-patches; +Cc: Richard Sandiford

On 10/18/2016 10:30 PM, David Malcolm wrote:
>
> I'm not in love with the names I chose in this patch.  It does seem odd
> having an "rtx_reader" class that can't actually read hierarchical rtx.
>
> How about "md_reader" as the base class (with responsibility for the
> things in read-md.o), and "rtx_reader" for the subclass (adding the
> things in read-rtl.o)?

I think a lot of renaming was for a variable (base_rtx_reader_ptr), not 
the class, wasn't it? I would very much like to avoid these, but I think 
for the class names it should be ok to go with what you suggest.


Bernd

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

* Re: RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-19 14:42               ` Bernd Schmidt
@ 2016-10-19 17:19                 ` David Malcolm
  2016-10-19 17:22                   ` Bernd Schmidt
  0 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-19 17:19 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches

On Wed, 2016-10-19 at 16:41 +0200, Bernd Schmidt wrote:
> On 10/19/2016 04:35 PM, David Malcolm wrote:
> 
> > In r241120 I dropped all dumping of the JUMP_LABEL when adding the
> > "compact" mode.
> > 
> > I'm now running into an issue with this as I update the __RTL in
> > cc1
> > tests to use the new format, since various passes require the
> > JUMP_INSNs to have JUMP_LABEL data.
> 
> Isn't it possible to recreate these? In jump.c we have 
> rebuild_jump_labels, which looks like it'll also compute LABEL_NUSES 
> which I think we were considering dropping in the output.

I already dropped LABEL_NUSES in compact mode in r241120; I think it's
possible to regenerate that information.

But how would we go about recreating the JUMP_LABEL data?  As far as I
can tell, it can be set up by reorg.c:make_return_insns
via comparison against function_return_label and
function_simple_return_label, which are set up by find_end_label; the
functions in question are non-trivial, and can lead to extra insns
being emitted.  Also, in shrink-wrap.c:handle_simple_exit, which has
similar state considerations.

It seems simpler to serialize this information.

Or am I missing something?

Thanks
Dave

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

* Re: RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-19 17:19                 ` David Malcolm
@ 2016-10-19 17:22                   ` Bernd Schmidt
  2016-10-19 17:54                     ` David Malcolm
  0 siblings, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-19 17:22 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/19/2016 07:19 PM, David Malcolm wrote:
> I already dropped LABEL_NUSES in compact mode in r241120; I think it's
> possible to regenerate that information.
>
> But how would we go about recreating the JUMP_LABEL data?  As far as I
> can tell, it can be set up by reorg.c:make_return_insns
> via comparison against function_return_label and
> function_simple_return_label, which are set up by find_end_label; the
> functions in question are non-trivial, and can lead to extra insns
> being emitted.  Also, in shrink-wrap.c:handle_simple_exit, which has
> similar state considerations.

I'd expect every return/simple_return insn to contain the corresponding 
rtx code. mark_jump_label_1 has this, which supports the theory:

     case RETURN:
     case SIMPLE_RETURN:
       if (is_target)
         {
           gcc_assert (JUMP_LABEL (insn) == NULL || JUMP_LABEL (insn) == x);
           JUMP_LABEL (insn) = x;
         }
       return;

This is called via mark_all_labels from rebuild_jump_labels_1, so it 
should Just Work - in theory.

> It seems simpler to serialize this information.

Simpler, probably, but it would be nice to omit it if it really is 
redundant.


Bernd

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

* Re: RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-19 17:22                   ` Bernd Schmidt
@ 2016-10-19 17:54                     ` David Malcolm
  0 siblings, 0 replies; 96+ messages in thread
From: David Malcolm @ 2016-10-19 17:54 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches

On Wed, 2016-10-19 at 19:22 +0200, Bernd Schmidt wrote:
> On 10/19/2016 07:19 PM, David Malcolm wrote:
> > I already dropped LABEL_NUSES in compact mode in r241120; I think
> > it's
> > possible to regenerate that information.
> > 
> > But how would we go about recreating the JUMP_LABEL data?  As far
> > as I
> > can tell, it can be set up by reorg.c:make_return_insns
> > via comparison against function_return_label and
> > function_simple_return_label, which are set up by find_end_label;
> > the
> > functions in question are non-trivial, and can lead to extra insns
> > being emitted.  Also, in shrink-wrap.c:handle_simple_exit, which
> > has
> > similar state considerations.
> 
> I'd expect every return/simple_return insn to contain the
> corresponding 
> rtx code. mark_jump_label_1 has this, which supports the theory:
> 
>      case RETURN:
>      case SIMPLE_RETURN:
>        if (is_target)
>          {
>            gcc_assert (JUMP_LABEL (insn) == NULL || JUMP_LABEL (insn)
> == x);
>            JUMP_LABEL (insn) = x;
>          }
>        return;
> 
> This is called via mark_all_labels from rebuild_jump_labels_1, so it 
> should Just Work - in theory.
> 
> > It seems simpler to serialize this information.
> 
> Simpler, probably, but it would be nice to omit it if it really is 
> redundant.

Thanks, that gave me the pointer I needed.  I think it is indeed
redundant and I'll work on regenerating it in class function_reader.

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

* INSN_UIDs again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-06 13:30   ` Bernd Schmidt
  2016-10-06 19:53     ` RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader) David Malcolm
@ 2016-10-20 13:55     ` David Malcolm
  2016-10-20 14:11       ` Bernd Schmidt
  1 sibling, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-20 13:55 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches

On Thu, 2016-10-06 at 15:30 +0200, Bernd Schmidt wrote:
> On 10/05/2016 06:15 PM, David Malcolm wrote:
> > +;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
> > +(insn 1045 0 1046 2 (set (reg:SI 480)
> > +        (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
> > +                    [flags 0xc0]
> > +                    <var_decl 0x7fa0363ea240
> > isl_obj_map_vtable>)))
> > +     y.c:12702 -1
> > +     (nil))
> > +(insn 1046 1045 1047 2 (set (reg/f:SI 479)
> > +        (lo_sum:SI (reg:SI 480)
> > +            (symbol_ref:SI ("isl_obj_map_vtable")
> > +               [flags 0xc0]
> > +               <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
> > +     y.c:12702 -1
> > +     (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
> > +                             [flags 0xc0]
> > +                             <var_decl 0x7fa0363ea240
> > isl_obj_map_vtable>)
> > +        (nil)))
> 
> I hate saying this, since you've obviously spent a lot of effort, but
> I 
> think we're still at a too early stage to construct testcases. One
> issue 
> that came up while discussing previous patch kits is that the format 
> here is still too verbose, and I'd like to settle on a format first. 
> There's all manner of things that are pointless in a testcase and
> impede 
> readability:
> 
>   * INSN_UIDs and NEXT/PREV fields (could be constructed from
> scratch,    except for labels)

Currently (as of r241120) the "compact" dump format omits NEXT/PRIV
fields, and only dumps INSN_UIDs for CODE_LABELs (and within
LABEL_REFs).  I've reimplemented the loader so that it copes with this,
preserving INSN_UIDs where provided, and generating others, ensuring
uniqueness.

I found myself making this change to a test case
(gcc.dg/rtl/x86_64/into-cfglayout.c):

     /* The conversion to cfglayout should eliminate unconditional jump
        instructions...  */
-/* { dg-final { scan-rtl-dump "Removing jump 14." "into_cfglayout" } }  */
-/* { dg-final { scan-rtl-dump-not "jump_insn 14" "into_cfglayout" } }  */
-/* { dg-final { scan-rtl-dump-not "barrier 15" "into_cfglayout" } }  */
+/* { dg-final { scan-rtl-dump "Removing jump 13." "into_cfglayout" } }  */
+/* { dg-final { scan-rtl-dump-not "jump_insn 13" "into_cfglayout" } }  */
+/* { dg-final { scan-rtl-dump-not "barrier" "into_cfglayout" } }  */
 
 /* ...but conditional jumps should be preserved.  */
-/* { dg-final { scan-rtl-dump "jump_insn 10" "into_cfglayout" } }  */
+/* { dg-final { scan-rtl-dump "jump_insn 9" "into_cfglayout" } }  */

All of the INSN_UIDs being referred to are implicitly generated by the
loader.

Presumably we want to allow for test cases like this that verify that a
specific insn was affected by a pass e.g. scanning for
  "Removing jump
14",
but having the INSN_UIDs be autogenerated seems to make this very
fragile (and makes the scan-rtl-dump directives hard to read).

Hence I'm leaning towards having the dump format contain explicit INSN_UIDs for all insns, not just CODE_LABELs (but omitting the NEXT/PREV, those are redundant noise).

Currently the jump insn in question looks like this:

      (cjump_insn (set (pc)
                    (label_ref 20)) 
                 (nil))

With explicit INSN_UIDs it would look like this:

      (cjump_insn 13 (set (pc)
                    (label_ref 20)) 
                 (nil))

Thoughts?
Dave

>   * INSN_CODE_NUMBERs in both textual and number form.
>   * Various (nil) fields
>   * VAR_DECL addresses.

[...snip...]

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

* Re: INSN_UIDs again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-20 13:55     ` INSN_UIDs " David Malcolm
@ 2016-10-20 14:11       ` Bernd Schmidt
  2016-10-20 14:20         ` David Malcolm
  2016-10-26 18:19         ` [PATCH] Show INSN_UIDs in compact mode David Malcolm
  0 siblings, 2 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-20 14:11 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/20/2016 03:55 PM, David Malcolm wrote:
> Currently the jump insn in question looks like this:
>
>       (cjump_insn (set (pc)
>                     (label_ref 20))
>                  (nil))
>
> With explicit INSN_UIDs it would look like this:
>
>       (cjump_insn 13 (set (pc)
>                     (label_ref 20))
>                  (nil))

Yeah, that wouldn't be so bad. It would also make it easier to make a 
-fdump-rtl-compact flag that changes the debugging dumps to use the 
compact format (we'd still need slightly different output for pseudos).

Still, I'd like to again encourage a mechanism where we can emit 
before/after dumps and have the compiler automatically compare them when 
running the test. That wouldn't run into this particular issue.


Bernd

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

* Re: INSN_UIDs again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-20 14:11       ` Bernd Schmidt
@ 2016-10-20 14:20         ` David Malcolm
  2016-10-20 14:22           ` Bernd Schmidt
  2016-10-26 18:19         ` [PATCH] Show INSN_UIDs in compact mode David Malcolm
  1 sibling, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-20 14:20 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches

On Thu, 2016-10-20 at 16:11 +0200, Bernd Schmidt wrote:
> On 10/20/2016 03:55 PM, David Malcolm wrote:
> > Currently the jump insn in question looks like this:
> > 
> >       (cjump_insn (set (pc)
> >                     (label_ref 20))
> >                  (nil))
> > 
> > With explicit INSN_UIDs it would look like this:
> > 
> >       (cjump_insn 13 (set (pc)
> >                     (label_ref 20))
> >                  (nil))
> 
> Yeah, that wouldn't be so bad. It would also make it easier to make a
> -fdump-rtl-compact flag that changes the debugging dumps to use the 
> compact format (we'd still need slightly different output for
> pseudos).
> 
> Still, I'd like to again encourage a mechanism where we can emit 
> before/after dumps and have the compiler automatically compare them
> when 
> running the test. That wouldn't run into this particular issue.

What kind of comparison would it do?

I'd be wary about a purely textual comparison (e.g. "diff") - it would
likely lead to fragile test cases, where minor changes to the output
format mean that all the test cases need regenerating (mea culpa, I
made this mistake in gcc-python-plugin's testsuite).

So presumably the comparison would involve loading the "expected-after"
version of the function, and doing some kind of function-level
comparison on the parsed result.  This sounds plausible, but would
likely be a significant expansion of the scope of the project, since
the existing RTL code is full of singleton global state (e.g. "crtl"
aka x_rtl).

So I'd prefer to leave this idea as a followup (and to implement the
"explicit INSN_UIDs for everything" idea).

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

* Re: INSN_UIDs again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader)
  2016-10-20 14:20         ` David Malcolm
@ 2016-10-20 14:22           ` Bernd Schmidt
  0 siblings, 0 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-20 14:22 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/20/2016 04:20 PM, David Malcolm wrote:
>
> What kind of comparison would it do?

Use read-rtl to read the "after" representation and compare it on the 
fly to what we actually have after running the pass under test.


Bernd

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

* Re: [PATCH 09/16] Split class rtx_reader into base_rtx_reader vs rtx_reader
  2016-10-19 14:45       ` Bernd Schmidt
@ 2016-10-20 19:14         ` Richard Sandiford
  0 siblings, 0 replies; 96+ messages in thread
From: Richard Sandiford @ 2016-10-20 19:14 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: David Malcolm, gcc-patches

Bernd Schmidt <bschmidt@redhat.com> writes:
> On 10/18/2016 10:30 PM, David Malcolm wrote:
>>
>> I'm not in love with the names I chose in this patch.  It does seem odd
>> having an "rtx_reader" class that can't actually read hierarchical rtx.
>>
>> How about "md_reader" as the base class (with responsibility for the
>> things in read-md.o), and "rtx_reader" for the subclass (adding the
>> things in read-rtl.o)?
>
> I think a lot of renaming was for a variable (base_rtx_reader_ptr), not 
> the class, wasn't it? I would very much like to avoid these, but I think 
> for the class names it should be ok to go with what you suggest.

FWIW, using md_reader and rtx_reader sounds good to me too.  These days
.md files contain more than just rtl (although everything retains the
same lispy syntax), so the names seem pretty natural.

Thanks,
Richard

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

* [PATCH] Show INSN_UIDs in compact mode
  2016-10-20 14:11       ` Bernd Schmidt
  2016-10-20 14:20         ` David Malcolm
@ 2016-10-26 18:19         ` David Malcolm
  2016-10-26 18:20           ` Bernd Schmidt
  1 sibling, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-10-26 18:19 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm

On Thu, 2016-10-20 at 16:11 +0200, Bernd Schmidt wrote:
> On 10/20/2016 03:55 PM, David Malcolm wrote:
> > Currently the jump insn in question looks like this:
> > 
> >       (cjump_insn (set (pc)
> >                     (label_ref 20))
> >                  (nil))
> > 
> > With explicit INSN_UIDs it would look like this:
> > 
> >       (cjump_insn 13 (set (pc)
> >                     (label_ref 20))
> >                  (nil))
> 
> Yeah, that wouldn't be so bad. It would also make it easier to make a
> -fdump-rtl-compact flag that changes the debugging dumps to use the
> compact format (we'd still need slightly different output for
> pseudos).

[...snip...]

The following patch adds back in the INSN_UID for all insns.

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.

OK for trunk?

gcc/ChangeLog:
	* print-rtl.c (rtx_writer::print_rtx_operand_code_u): Print
	INSN_UIDs for all insns in compact mode.
	(rtx_writer::print_rtx): Likewise.
	* print-rtl.h (rtx_writer::flag_compact): Update comment.
	* rtl-tests.c (selftest::test_dumping_insns): Update expected
	output to include INSN_UID.
	(selftest::test_uncond_jump): Likewise.
---
 gcc/print-rtl.c | 10 ++++------
 gcc/print-rtl.h |  2 +-
 gcc/rtl-tests.c |  4 ++--
 3 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index d0ba896..341ecdf 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -423,8 +423,8 @@ rtx_writer::print_rtx_operand_code_r (const_rtx in_rtx)
 void
 rtx_writer::print_rtx_operand_code_u (const_rtx in_rtx, int idx)
 {
-  /* Don't print insn UIDs in compact mode, apart from in LABEL_REFs.  */
-  if (m_compact && GET_CODE (in_rtx) != LABEL_REF)
+  /* Don't print insn UIDs for PREV/NEXT_INSN in compact mode.  */
+  if (m_compact && INSN_CHAIN_CODE_P (GET_CODE (in_rtx)) && idx < 2)
     return;
 
   if (XEXP (in_rtx, idx) != NULL)
@@ -672,10 +672,8 @@ rtx_writer::print_rtx (const_rtx in_rtx)
     idx = 5;
 #endif
 
-  /* For insns, print the INSN_UID.
-     In compact mode, we only print the INSN_UID of CODE_LABELs.  */
-  if (INSN_CHAIN_CODE_P (GET_CODE (in_rtx))
-      && (!m_compact || GET_CODE (in_rtx) == CODE_LABEL))
+  /* For insns, print the INSN_UID.  */
+  if (INSN_CHAIN_CODE_P (GET_CODE (in_rtx)))
     {
       if (flag_dump_unnumbered)
 	fprintf (m_outfile, " #");
diff --git a/gcc/print-rtl.h b/gcc/print-rtl.h
index 4ebfcf9..8496ffa 100644
--- a/gcc/print-rtl.h
+++ b/gcc/print-rtl.h
@@ -50,7 +50,7 @@ class rtx_writer
   bool m_simple;
 
   /* If true, use compact dump format:
-     - INSN_UIDs are omitted, except for jumps and CODE_LABELs,
+     - PREV/NEXT_INSN UIDs are omitted
      - INSN_CODEs are omitted,
      - register numbers are omitted for hard and virtual regs, and
        non-virtual pseudos are offset relative to the first such reg, and
diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
index 43665ba..4e534b2 100644
--- a/gcc/rtl-tests.c
+++ b/gcc/rtl-tests.c
@@ -121,7 +121,7 @@ test_dumping_insns ()
   /* Barriers.  */
   rtx_barrier *barrier = as_a <rtx_barrier *> (rtx_alloc (BARRIER));
   SET_NEXT_INSN (barrier) = NULL;
-  ASSERT_RTL_DUMP_EQ ("(cbarrier)\n", barrier);
+  ASSERT_RTL_DUMP_EQ ("(cbarrier 0)\n", barrier);
 
   /* Labels.  */
   rtx_insn *label = gen_label_rtx ();
@@ -179,7 +179,7 @@ test_uncond_jump ()
   ASSERT_TRUE (onlyjump_p (jump_insn));
   ASSERT_TRUE (control_flow_insn_p (jump_insn));
 
-  ASSERT_RTL_DUMP_EQ ("(cjump_insn (set (pc)\n"
+  ASSERT_RTL_DUMP_EQ ("(cjump_insn 1 (set (pc)\n"
 		      "        (label_ref 0))\n"
 		      "     (nil))\n",
 		      jump_insn);
-- 
1.8.5.3

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

* Re: [PATCH] Show INSN_UIDs in compact mode
  2016-10-26 18:19         ` [PATCH] Show INSN_UIDs in compact mode David Malcolm
@ 2016-10-26 18:20           ` Bernd Schmidt
  0 siblings, 0 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-10-26 18:20 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 10/26/2016 08:50 PM, David Malcolm wrote:
>
> The following patch adds back in the INSN_UID for all insns.
>
> Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.
>
> OK for trunk?

Yes.

Bernd

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

* [PATCH] Introduce emit_status::ensure_regno_capacity (v5)
  2016-10-05 15:55   ` Bernd Schmidt
@ 2016-11-18 20:47     ` David Malcolm
  2016-11-22 13:34       ` Bernd Schmidt
  0 siblings, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-11-18 20:47 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm

On Wed, 2016-10-05 at 17:55 +0200, Bernd Schmidt wrote:
> On 10/05/2016 06:15 PM, David Malcolm wrote:
> > -  /* Make sure regno_pointer_align, and regno_reg_rtx are large
> > -     enough to have an element for this pseudo reg number.  */
> > +  int cur_size = crtl->emit.regno_pointer_align_length;
> > +  if (reg_rtx_no == cur_size)
> > +    crtl->emit.ensure_regno_capacity (cur_size * 2);
> 
> Patch looks ok in principle, but maybe this manipulation of the size
> should be part of the new function as well - i.e. don't pass a
> new_size
> to it, make it check reg_rtx_no itself.

Changed in this version
- dropped "new_size" argument
- added a while loop to cover the case where reg_rtx_no
  needs to grow by more the double (potentially needed
  when loading RTL dumps)
- added a gcc_assert to ensure that the buffer is large enough

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu as
part of the patch kit.

OK for trunk? (assuming it tests OK individually)

gcc/ChangeLog:
	* emit-rtl.c (gen_reg_rtx): Move regno_pointer_align and
	regno_reg_rtx resizing logic to...
	(emit_status::ensure_regno_capacity): ...this new method,
	and ensure that the buffers are large enough.
	(init_emit): Allocate regno_reg_rtx using ggc_cleared_vec_alloc
	rather than ggc_vec_alloc.
	* function.h (emit_status::ensure_regno_capacity): New method.
---
 gcc/emit-rtl.c | 48 +++++++++++++++++++++++++++++-------------------
 gcc/function.h |  2 ++
 2 files changed, 31 insertions(+), 19 deletions(-)

diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index e995899..b2b5fde 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1057,29 +1057,38 @@ gen_reg_rtx (machine_mode mode)
   /* Do not call gen_reg_rtx with uninitialized crtl.  */
   gcc_assert (crtl->emit.regno_pointer_align_length);
 
-  /* Make sure regno_pointer_align, and regno_reg_rtx are large
-     enough to have an element for this pseudo reg number.  */
+  crtl->emit.ensure_regno_capacity ();
+  gcc_assert (reg_rtx_no < crtl->emit.regno_pointer_align_length);
 
-  if (reg_rtx_no == crtl->emit.regno_pointer_align_length)
-    {
-      int old_size = crtl->emit.regno_pointer_align_length;
-      char *tmp;
-      rtx *new1;
+  val = gen_raw_REG (mode, reg_rtx_no);
+  regno_reg_rtx[reg_rtx_no++] = val;
+  return val;
+}
 
-      tmp = XRESIZEVEC (char, crtl->emit.regno_pointer_align, old_size * 2);
-      memset (tmp + old_size, 0, old_size);
-      crtl->emit.regno_pointer_align = (unsigned char *) tmp;
+/* Make sure m_regno_pointer_align, and regno_reg_rtx are large
+   enough to have elements in the range 0 <= idx <= reg_rtx_no.  */
 
-      new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, old_size * 2);
-      memset (new1 + old_size, 0, old_size * sizeof (rtx));
-      regno_reg_rtx = new1;
+void
+emit_status::ensure_regno_capacity ()
+{
+  int old_size = regno_pointer_align_length;
 
-      crtl->emit.regno_pointer_align_length = old_size * 2;
-    }
+  if (reg_rtx_no < old_size)
+    return;
 
-  val = gen_raw_REG (mode, reg_rtx_no);
-  regno_reg_rtx[reg_rtx_no++] = val;
-  return val;
+  int new_size = old_size * 2;
+  while (reg_rtx_no >= new_size)
+    new_size *= 2;
+
+  char *tmp = XRESIZEVEC (char, regno_pointer_align, new_size);
+  memset (tmp + old_size, 0, new_size - old_size);
+  regno_pointer_align = (unsigned char *) tmp;
+
+  rtx *new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, new_size);
+  memset (new1 + old_size, 0, (new_size - old_size) * sizeof (rtx));
+  regno_reg_rtx = new1;
+
+  crtl->emit.regno_pointer_align_length = new_size;
 }
 
 /* Return TRUE if REG is a PARM_DECL, FALSE otherwise.  */
@@ -5667,7 +5676,8 @@ init_emit (void)
   crtl->emit.regno_pointer_align
     = XCNEWVEC (unsigned char, crtl->emit.regno_pointer_align_length);
 
-  regno_reg_rtx = ggc_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
+  regno_reg_rtx =
+    ggc_cleared_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
 
   /* Put copies of all the hard registers into regno_reg_rtx.  */
   memcpy (regno_reg_rtx,
diff --git a/gcc/function.h b/gcc/function.h
index b564f45..cabffb9 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -34,6 +34,8 @@ struct GTY(()) sequence_stack {
 };
 \f
 struct GTY(()) emit_status {
+  void ensure_regno_capacity ();
+
   /* This is reset to LAST_VIRTUAL_REGISTER + 1 at the start of each function.
      After rtl generation, it is 1 plus the largest register number used.  */
   int x_reg_rtx_no;
-- 
1.8.5.3

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

* Re: [PATCH] (v2) Add a "compact" mode to print_rtx_function
  2016-10-12 20:06                 ` [PATCH] (v2) " David Malcolm
  2016-10-13 10:21                   ` Bernd Schmidt
@ 2016-11-22 13:18                   ` Dominik Vogt
  2016-11-22 13:32                     ` Bernd Schmidt
  1 sibling, 1 reply; 96+ messages in thread
From: Dominik Vogt @ 2016-11-22 13:18 UTC (permalink / raw)
  To: David Malcolm; +Cc: Bernd Schmidt, gcc-patches

On Wed, Oct 12, 2016 at 04:37:26PM -0400, David Malcolm wrote:
> On Wed, 2016-10-12 at 19:31 +0200, Bernd Schmidt wrote:
> > On 10/12/2016 07:48 PM, David Malcolm wrote:
> > > This patch implements a "compact" mode for print_rtx_function,
> > > implementing most of the ideas above.
> > > 
> > > Example of output can be seen here:
> > >   https://dmalcolm.fedorapeople.org/gcc/2016-10-12/test-switch-comp
> > > act.rtl
> > > which can be contrasted with the non-compact output here:
> > >   https://dmalcolm.fedorapeople.org/gcc/2016-10-12/test-switch-nonc
> > > ompact.rtl
> > > 
> > > It adds the "c" prefix to the insn names, so we get "cinsn", etc. 
> > >  However,
> > > it does lead to things like this:
> > > 
> > >    (ccode_label 56 8 "")
> > > 
> > > which gives me pause: would the "ccode" in "ccode_label" be
> > > confusing? (compared
> > > to "ccmode").  An alternative might be to have a "compact-insn
> > > -chain" vs
> > > "insn-chain" wrapper element, expressing that this is a compact
> > > dump.

> --- a/gcc/print-rtl.c
> +++ b/gcc/print-rtl.c
...
> @@ -284,7 +292,7 @@ print_rtx_operand_code_i (const_rtx in_rtx, int idx)
>        if (INSN_HAS_LOCATION (in_insn))
>  	{
>  	  expanded_location xloc = insn_location (in_insn);
> -	  fprintf (outfile, " %s:%i", xloc.file, xloc.line);
> +	  fprintf (outfile, " \"%s\":%i", xloc.file, xloc.line);

Was this change intentional?  We've got to update a scan-assembler
statement in an s390 test to reflect the additional double quotes
in the output string.  Not a big deal, just wanted to make sure
this is not an accident.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

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

* Re: [PATCH] (v2) Add a "compact" mode to print_rtx_function
  2016-11-22 13:18                   ` [PATCH] (v2) Add a "compact" mode to print_rtx_function Dominik Vogt
@ 2016-11-22 13:32                     ` Bernd Schmidt
  2016-11-22 13:37                       ` Jakub Jelinek
  0 siblings, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-11-22 13:32 UTC (permalink / raw)
  To: vogt, David Malcolm, gcc-patches

On 11/22/2016 02:18 PM, Dominik Vogt wrote:

>> @@ -284,7 +292,7 @@ print_rtx_operand_code_i (const_rtx in_rtx, int idx)
>>        if (INSN_HAS_LOCATION (in_insn))
>>  	{
>>  	  expanded_location xloc = insn_location (in_insn);
>> -	  fprintf (outfile, " %s:%i", xloc.file, xloc.line);
>> +	  fprintf (outfile, " \"%s\":%i", xloc.file, xloc.line);
>
> Was this change intentional?  We've got to update a scan-assembler
> statement in an s390 test to reflect the additional double quotes
> in the output string.  Not a big deal, just wanted to make sure
> this is not an accident.

The idea was to make the output less ambiguous for file names with spaces.


Bernd

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

* Re: [PATCH] Introduce emit_status::ensure_regno_capacity (v5)
  2016-11-18 20:47     ` [PATCH] Introduce emit_status::ensure_regno_capacity (v5) David Malcolm
@ 2016-11-22 13:34       ` Bernd Schmidt
  0 siblings, 0 replies; 96+ messages in thread
From: Bernd Schmidt @ 2016-11-22 13:34 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 11/18/2016 10:19 PM, David Malcolm wrote:
>
> -  regno_reg_rtx = ggc_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
> +  regno_reg_rtx =
> +    ggc_cleared_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);

When wrapping lines, put the operator first.

Otherwise ok.


Bernd

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

* Re: [PATCH] (v2) Add a "compact" mode to print_rtx_function
  2016-11-22 13:32                     ` Bernd Schmidt
@ 2016-11-22 13:37                       ` Jakub Jelinek
  2016-11-22 14:25                         ` David Malcolm
  2016-11-22 14:38                         ` Bernd Schmidt
  0 siblings, 2 replies; 96+ messages in thread
From: Jakub Jelinek @ 2016-11-22 13:37 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: vogt, David Malcolm, gcc-patches

On Tue, Nov 22, 2016 at 02:32:39PM +0100, Bernd Schmidt wrote:
> On 11/22/2016 02:18 PM, Dominik Vogt wrote:
> 
> >>@@ -284,7 +292,7 @@ print_rtx_operand_code_i (const_rtx in_rtx, int idx)
> >>       if (INSN_HAS_LOCATION (in_insn))
> >> 	{
> >> 	  expanded_location xloc = insn_location (in_insn);
> >>-	  fprintf (outfile, " %s:%i", xloc.file, xloc.line);
> >>+	  fprintf (outfile, " \"%s\":%i", xloc.file, xloc.line);
> >
> >Was this change intentional?  We've got to update a scan-assembler
> >statement in an s390 test to reflect the additional double quotes
> >in the output string.  Not a big deal, just wanted to make sure
> >this is not an accident.
> 
> The idea was to make the output less ambiguous for file names with spaces.

Can't it be done only if xloc.file contains any fancy characters?
If it does (where fancy should be anything other than [a-zA-Z/_0-9.-] or
some other reasonable definition, certainly space, quotes, backslash, etc. would count),
shouldn't we adjust it (e.g. use \" instead of ", handle control characters
etc.)?

	Jakub

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

* Re: [PATCH] (v2) Add a "compact" mode to print_rtx_function
  2016-11-22 13:37                       ` Jakub Jelinek
@ 2016-11-22 14:25                         ` David Malcolm
  2016-11-22 14:39                           ` Dominik Vogt
  2016-11-22 14:38                         ` Bernd Schmidt
  1 sibling, 1 reply; 96+ messages in thread
From: David Malcolm @ 2016-11-22 14:25 UTC (permalink / raw)
  To: Jakub Jelinek, Bernd Schmidt; +Cc: vogt, gcc-patches

On Tue, 2016-11-22 at 14:37 +0100, Jakub Jelinek wrote:
> On Tue, Nov 22, 2016 at 02:32:39PM +0100, Bernd Schmidt wrote:
> > On 11/22/2016 02:18 PM, Dominik Vogt wrote:
> > 
> > > > @@ -284,7 +292,7 @@ print_rtx_operand_code_i (const_rtx in_rtx,
> > > > int idx)
> > > >       if (INSN_HAS_LOCATION (in_insn))
> > > > 	{
> > > > 	  expanded_location xloc = insn_location (in_insn);
> > > > -	  fprintf (outfile, " %s:%i", xloc.file, xloc.line);
> > > > +	  fprintf (outfile, " \"%s\":%i", xloc.file,
> > > > xloc.line);
> > > 
> > > Was this change intentional?  We've got to update a scan
> > > -assembler
> > > statement in an s390 test to reflect the additional double quotes
> > > in the output string.  Not a big deal, just wanted to make sure
> > > this is not an accident.

Sorry about the breakage.

How widespread is the problem?

> > The idea was to make the output less ambiguous for file names with
> > spaces.
> 
> Can't it be done only if xloc.file contains any fancy characters?
> If it does (where fancy should be anything other than [a-zA-Z/_0-9.-]
> or
> some other reasonable definition, certainly space, quotes, backslash,
> etc. would count),
> shouldn't we adjust it (e.g. use \" instead of ", handle control
> characters
> etc.)?

The idea was that quotes also make the output somewhat easier for the
RTL frontend to parse, though reading the latest version of the RTL
frontend patches, it looks like I don't make use of them yet.

Another approach would be to only use the quotes when the dump is in
"compact" mode, since compact mode is the format that the RTL frontend
parses: the RTL dumps emitted by DejaGnu don't use it, instead using
the older style.

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

* Re: [PATCH] (v2) Add a "compact" mode to print_rtx_function
  2016-11-22 13:37                       ` Jakub Jelinek
  2016-11-22 14:25                         ` David Malcolm
@ 2016-11-22 14:38                         ` Bernd Schmidt
  2016-11-22 14:45                           ` Jakub Jelinek
  1 sibling, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-11-22 14:38 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: vogt, David Malcolm, gcc-patches

On 11/22/2016 02:37 PM, Jakub Jelinek wrote:
> Can't it be done only if xloc.file contains any fancy characters?

Sure, but why? Strings generally get emitted with quotes around them, I 
don't see a good reason for filenames to be different, especially if it 
makes the output easier to parse.

> If it does (where fancy should be anything other than [a-zA-Z/_0-9.-] or
> some other reasonable definition, certainly space, quotes, backslash, etc. would count),
> shouldn't we adjust it (e.g. use \" instead of ", handle control characters
> etc.)?

The way I see it, spaces in filenames are regrettably somewhat common. 
Backslashes and quotes rather less so, to the point I really don't see a 
need to worry about them at the moment, and the necessary quoting could 
be added later if really necessary.


Bernd

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

* Re: [PATCH] (v2) Add a "compact" mode to print_rtx_function
  2016-11-22 14:25                         ` David Malcolm
@ 2016-11-22 14:39                           ` Dominik Vogt
  0 siblings, 0 replies; 96+ messages in thread
From: Dominik Vogt @ 2016-11-22 14:39 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jakub Jelinek, Bernd Schmidt, gcc-patches

On Tue, Nov 22, 2016 at 09:25:03AM -0500, David Malcolm wrote:
> On Tue, 2016-11-22 at 14:37 +0100, Jakub Jelinek wrote:
> > On Tue, Nov 22, 2016 at 02:32:39PM +0100, Bernd Schmidt wrote:
> > > On 11/22/2016 02:18 PM, Dominik Vogt wrote:
> > > 
> > > > > @@ -284,7 +292,7 @@ print_rtx_operand_code_i (const_rtx in_rtx,
> > > > > int idx)
> > > > >       if (INSN_HAS_LOCATION (in_insn))
> > > > > 	{
> > > > > 	  expanded_location xloc = insn_location (in_insn);
> > > > > -	  fprintf (outfile, " %s:%i", xloc.file, xloc.line);
> > > > > +	  fprintf (outfile, " \"%s\":%i", xloc.file,
> > > > > xloc.line);
> > > > 
> > > > Was this change intentional?  We've got to update a scan
> > > > -assembler
> > > > statement in an s390 test to reflect the additional double quotes
> > > > in the output string.  Not a big deal, just wanted to make sure
> > > > this is not an accident.
> 
> Sorry about the breakage.
> 
> How widespread is the problem?

In the s390 tests, it is only a single scan-assembler.  Not sure
whether these are affected or not:

gcc.dg/debug/dwarf2/pr29609-1.c:/* { dg-final { scan-assembler "pr29609-1.c:18" } } */
gcc.dg/debug/dwarf2/pr29609-2.c:/* { dg-final { scan-assembler "pr29609-2.c:27" } } */
...
gcc.dg/debug/dwarf2/pr36690-1.c:/* { dg-final { scan-assembler "pr36690-1.c:11" } } */
gcc.dg/debug/dwarf2/pr36690-2.c:/* { dg-final { scan-assembler "pr36690-2.c:24" } } */
gcc.dg/debug/dwarf2/pr36690-3.c:/* { dg-final { scan-assembler "pr36690-3.c:19" } } */
...
gcc.dg/debug/dwarf2/pr37616.c:/* { dg-final { scan-assembler "pr37616.c:17" } } */
...
gcc.dg/debug/dwarf2/short-circuit.c:/* { dg-final { scan-assembler "short-circuit.c:11" } } */
...

(List generated with

  $ cd testsuite
  $ grep -r "scan-assembler.*[.]c.\?.\?.\?:" .
)

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

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

* Re: [PATCH] (v2) Add a "compact" mode to print_rtx_function
  2016-11-22 14:38                         ` Bernd Schmidt
@ 2016-11-22 14:45                           ` Jakub Jelinek
  2016-11-22 15:38                             ` David Malcolm
  0 siblings, 1 reply; 96+ messages in thread
From: Jakub Jelinek @ 2016-11-22 14:45 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: vogt, David Malcolm, gcc-patches

On Tue, Nov 22, 2016 at 03:38:04PM +0100, Bernd Schmidt wrote:
> On 11/22/2016 02:37 PM, Jakub Jelinek wrote:
> >Can't it be done only if xloc.file contains any fancy characters?
> 
> Sure, but why? Strings generally get emitted with quotes around them, I
> don't see a good reason for filenames to be different, especially if it
> makes the output easier to parse.

Because printing common filenames matches what we emit in diagnostics,
what e.g. sanitizers emit at runtime diagnostics, what we emit as locations
in gimple dumps etc.

	Jakub

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

* Re: [PATCH] (v2) Add a "compact" mode to print_rtx_function
  2016-11-22 14:45                           ` Jakub Jelinek
@ 2016-11-22 15:38                             ` David Malcolm
  2016-11-25 16:37                               ` Dominik Vogt
  2016-12-01 10:13                               ` [PING] " Dominik Vogt
  0 siblings, 2 replies; 96+ messages in thread
From: David Malcolm @ 2016-11-22 15:38 UTC (permalink / raw)
  To: Jakub Jelinek, Bernd Schmidt; +Cc: vogt, gcc-patches

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

On Tue, 2016-11-22 at 15:45 +0100, Jakub Jelinek wrote:
> On Tue, Nov 22, 2016 at 03:38:04PM +0100, Bernd Schmidt wrote:
> > On 11/22/2016 02:37 PM, Jakub Jelinek wrote:
> > > Can't it be done only if xloc.file contains any fancy characters?
> > 
> > Sure, but why? Strings generally get emitted with quotes around
> > them, I
> > don't see a good reason for filenames to be different, especially
> > if it
> > makes the output easier to parse.
> 
> Because printing common filenames matches what we emit in
> diagnostics,
> what e.g. sanitizers emit at runtime diagnostics, what we emit as
> locations
> in gimple dumps etc.

It sounds like a distinction between human-readable vs machine
-readable.

How about something like the following, which only adds the quotes if
outputting the RTL FE's input format?

Does this fix the failing tests?

[-- Attachment #2: 0001-print-rtl.c-conditionalize-quotes-for-filenames.patch --]
[-- Type: text/x-patch, Size: 969 bytes --]

From 642d511fdba3a33fb18ce46c549f7c972ed6b14e Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 22 Nov 2016 11:06:41 -0500
Subject: [PATCH] print-rtl.c: conditionalize quotes for filenames

gcc/ChangeLog:
	* print-rtl.c (rtx_writer::print_rtx_operand_code_i): Only use
	quotes for filenames when in compact mode.
---
 gcc/print-rtl.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 77e6b05..5370602 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -371,7 +371,10 @@ rtx_writer::print_rtx_operand_code_i (const_rtx in_rtx, int idx)
       if (INSN_HAS_LOCATION (in_insn))
 	{
 	  expanded_location xloc = insn_location (in_insn);
-	  fprintf (m_outfile, " \"%s\":%i", xloc.file, xloc.line);
+	  if (m_compact)
+	    fprintf (m_outfile, " \"%s\":%i", xloc.file, xloc.line);
+	  else
+	    fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);
 	}
 #endif
     }
-- 
1.8.5.3


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

* Re: [PATCH] (v2) Add a "compact" mode to print_rtx_function
  2016-11-22 15:38                             ` David Malcolm
@ 2016-11-25 16:37                               ` Dominik Vogt
  2016-12-01 10:13                               ` [PING] " Dominik Vogt
  1 sibling, 0 replies; 96+ messages in thread
From: Dominik Vogt @ 2016-11-25 16:37 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jakub Jelinek, Bernd Schmidt, gcc-patches

On Tue, Nov 22, 2016 at 10:38:42AM -0500, David Malcolm wrote:
> On Tue, 2016-11-22 at 15:45 +0100, Jakub Jelinek wrote:
> > On Tue, Nov 22, 2016 at 03:38:04PM +0100, Bernd Schmidt wrote:
> > > On 11/22/2016 02:37 PM, Jakub Jelinek wrote:
> > > > Can't it be done only if xloc.file contains any fancy characters?
> > > 
> > > Sure, but why? Strings generally get emitted with quotes around
> > > them, I
> > > don't see a good reason for filenames to be different, especially
> > > if it
> > > makes the output easier to parse.
> > 
> > Because printing common filenames matches what we emit in
> > diagnostics,
> > what e.g. sanitizers emit at runtime diagnostics, what we emit as
> > locations
> > in gimple dumps etc.
> 
> It sounds like a distinction between human-readable vs machine
> -readable.
> 
> How about something like the following, which only adds the quotes if
> outputting the RTL FE's input format?
> 
> Does this fix the failing tests?

Yep.

> --- a/gcc/print-rtl.c
> +++ b/gcc/print-rtl.c
> @@ -371,7 +371,10 @@ rtx_writer::print_rtx_operand_code_i (const_rtx in_rtx, int idx)
>        if (INSN_HAS_LOCATION (in_insn))
>  	{
>  	  expanded_location xloc = insn_location (in_insn);
> -	  fprintf (m_outfile, " \"%s\":%i", xloc.file, xloc.line);
> +	  if (m_compact)
> +	    fprintf (m_outfile, " \"%s\":%i", xloc.file, xloc.line);
> +	  else
> +	    fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);

Looks sensible to me.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

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

* Re: [PING] (v2) Add a "compact" mode to print_rtx_function
  2016-11-22 15:38                             ` David Malcolm
  2016-11-25 16:37                               ` Dominik Vogt
@ 2016-12-01 10:13                               ` Dominik Vogt
  2016-12-01 12:28                                 ` Bernd Schmidt
  1 sibling, 1 reply; 96+ messages in thread
From: Dominik Vogt @ 2016-12-01 10:13 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jakub Jelinek, Bernd Schmidt, gcc-patches

On Tue, Nov 22, 2016 at 10:38:42AM -0500, David Malcolm wrote:
> On Tue, 2016-11-22 at 15:45 +0100, Jakub Jelinek wrote:
> > On Tue, Nov 22, 2016 at 03:38:04PM +0100, Bernd Schmidt wrote:
> > > On 11/22/2016 02:37 PM, Jakub Jelinek wrote:
> > > > Can't it be done only if xloc.file contains any fancy characters?
> > > 
> > > Sure, but why? Strings generally get emitted with quotes around
> > > them, I
> > > don't see a good reason for filenames to be different, especially
> > > if it
> > > makes the output easier to parse.
> > 
> > Because printing common filenames matches what we emit in
> > diagnostics,
> > what e.g. sanitizers emit at runtime diagnostics, what we emit as
> > locations
> > in gimple dumps etc.
> 
> It sounds like a distinction between human-readable vs machine
> -readable.
> 
> How about something like the following, which only adds the quotes if
> outputting the RTL FE's input format?
> 
> Does this fix the failing tests?

> From 642d511fdba3a33fb18ce46c549f7c972ed6b14e Mon Sep 17 00:00:00 2001
> From: David Malcolm <dmalcolm@redhat.com>
> Date: Tue, 22 Nov 2016 11:06:41 -0500
> Subject: [PATCH] print-rtl.c: conditionalize quotes for filenames
> 
> gcc/ChangeLog:
> 	* print-rtl.c (rtx_writer::print_rtx_operand_code_i): Only use
> 	quotes for filenames when in compact mode.
> ---
>  gcc/print-rtl.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
> index 77e6b05..5370602 100644
> --- a/gcc/print-rtl.c
> +++ b/gcc/print-rtl.c
> @@ -371,7 +371,10 @@ rtx_writer::print_rtx_operand_code_i (const_rtx in_rtx, int idx)
>        if (INSN_HAS_LOCATION (in_insn))
>  	{
>  	  expanded_location xloc = insn_location (in_insn);
> -	  fprintf (m_outfile, " \"%s\":%i", xloc.file, xloc.line);
> +	  if (m_compact)
> +	    fprintf (m_outfile, " \"%s\":%i", xloc.file, xloc.line);
> +	  else
> +	    fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);
>  	}
>  #endif
>      }
> -- 
> 1.8.5.3

I'd like to get our test failure fixed, either by changing
print-rtl.c or our test case.  Is the above patch good for trunk?
It does fix the s390 test failure.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany

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

* Re: [PING] (v2) Add a "compact" mode to print_rtx_function
  2016-12-01 10:13                               ` [PING] " Dominik Vogt
@ 2016-12-01 12:28                                 ` Bernd Schmidt
  2016-12-02 12:36                                   ` Andreas Krebbel
  0 siblings, 1 reply; 96+ messages in thread
From: Bernd Schmidt @ 2016-12-01 12:28 UTC (permalink / raw)
  To: vogt, David Malcolm, Jakub Jelinek, gcc-patches

On 12/01/2016 11:12 AM, Dominik Vogt wrote:
>>
>> diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
>> index 77e6b05..5370602 100644
>> --- a/gcc/print-rtl.c
>> +++ b/gcc/print-rtl.c
>> @@ -371,7 +371,10 @@ rtx_writer::print_rtx_operand_code_i (const_rtx in_rtx, int idx)
>>        if (INSN_HAS_LOCATION (in_insn))
>>  	{
>>  	  expanded_location xloc = insn_location (in_insn);
>> -	  fprintf (m_outfile, " \"%s\":%i", xloc.file, xloc.line);
>> +	  if (m_compact)
>> +	    fprintf (m_outfile, " \"%s\":%i", xloc.file, xloc.line);
>> +	  else
>> +	    fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);
>>  	}
>>  #endif
>>      }
>> --
>> 1.8.5.3
>
> I'd like to get our test failure fixed, either by changing
> print-rtl.c or our test case.  Is the above patch good for trunk?
> It does fix the s390 test failure.

I still don't see a strong reason not to print the quotes, so I'd 
suggest changing the testcase.


Bernd

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

* Re: [PING] (v2) Add a "compact" mode to print_rtx_function
  2016-12-01 12:28                                 ` Bernd Schmidt
@ 2016-12-02 12:36                                   ` Andreas Krebbel
  0 siblings, 0 replies; 96+ messages in thread
From: Andreas Krebbel @ 2016-12-02 12:36 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: gcc-patches

On Thu, Dec 01, 2016 at 01:27:55PM +0100, Bernd Schmidt wrote:
> On 12/01/2016 11:12 AM, Dominik Vogt wrote:
...
> >I'd like to get our test failure fixed, either by changing
> >print-rtl.c or our test case.  Is the above patch good for trunk?
> >It does fix the s390 test failure.
> 
> I still don't see a strong reason not to print the quotes, so I'd
> suggest changing the testcase.

Ok. I've just committed
https://gcc.gnu.org/ml/gcc-patches/2016-12/msg00084.html

Bye,

-Andreas-

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

end of thread, other threads:[~2016-12-02 12:36 UTC | newest]

Thread overview: 96+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-05 15:44 [PATCH 00/16] RTL frontend (v3) David Malcolm
2016-10-05 15:44 ` [PATCH 08/16] (partially-approved): Introduce selftest::locate_file David Malcolm
2016-10-05 16:10   ` Bernd Schmidt
2016-10-05 15:44 ` [PATCH 07/16] read-md: add some helper functions David Malcolm
2016-10-05 15:57   ` Bernd Schmidt
2016-10-05 15:44 ` [PATCH 11/16] df selftests (v3) David Malcolm
2016-10-05 15:44 ` [PATCH 01/16] read-md.c: Add various cleanups to ~rtx_reader David Malcolm
2016-10-05 15:51   ` Bernd Schmidt
2016-10-11 15:15     ` David Malcolm
2016-10-12 21:57       ` Richard Sandiford
2016-10-14 17:45         ` [PATCH] read-md.c: Move various state to within class rtx_reader David Malcolm
2016-10-17 11:05           ` Bernd Schmidt
2016-10-17 11:37           ` Richard Sandiford
2016-10-17 16:27             ` [PATCH] read-md.c: Move various state to within class rtx_reader (v3) David Malcolm
2016-10-17 20:23               ` Richard Sandiford
2016-10-05 15:45 ` [PATCH 02/16] (approved) Add selftest::read_file David Malcolm
2016-10-05 15:45 ` [PATCH 13/16] cse.c selftests David Malcolm
2016-10-05 15:45 ` [PATCH 12/16] combine.c selftests (v2) David Malcolm
2016-10-05 15:45 ` [PATCH 10/16] Introduce class function_reader (v3) David Malcolm
2016-10-05 16:00   ` Bernd Schmidt
2016-10-07 13:44     ` David Malcolm
2016-10-10 18:53       ` Richard Sandiford
2016-10-05 15:45 ` [PATCH 05/16] Introduce rtl_data::init_stack_alignment David Malcolm
2016-10-05 15:52   ` Bernd Schmidt
2016-10-05 15:45 ` [PATCH 15/16] RTL frontend (rtl1), on top of dump reader David Malcolm
2016-10-06 13:30   ` Bernd Schmidt
2016-10-06 19:53     ` RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader) David Malcolm
2016-10-06 19:59       ` David Malcolm
2016-10-07 10:38       ` Bernd Schmidt
2016-10-07 13:27         ` David Malcolm
2016-10-07 13:58           ` Bernd Schmidt
2016-10-07 18:08             ` David Malcolm
2016-10-12 10:45             ` [PATCH] print_rtx_function: integrate dumping of the CFG into the insn chain David Malcolm
2016-10-12 10:50               ` Bernd Schmidt
2016-10-12 17:17             ` [PATCH] Add a "compact" mode to print_rtx_function David Malcolm
2016-10-12 17:31               ` Bernd Schmidt
2016-10-12 20:06                 ` [PATCH] (v2) " David Malcolm
2016-10-13 10:21                   ` Bernd Schmidt
2016-10-13 15:22                     ` [PATCH] Omit INSN_LOCATION from compact dumps David Malcolm
2016-10-13 15:50                       ` Bernd Schmidt
2016-11-22 13:18                   ` [PATCH] (v2) Add a "compact" mode to print_rtx_function Dominik Vogt
2016-11-22 13:32                     ` Bernd Schmidt
2016-11-22 13:37                       ` Jakub Jelinek
2016-11-22 14:25                         ` David Malcolm
2016-11-22 14:39                           ` Dominik Vogt
2016-11-22 14:38                         ` Bernd Schmidt
2016-11-22 14:45                           ` Jakub Jelinek
2016-11-22 15:38                             ` David Malcolm
2016-11-25 16:37                               ` Dominik Vogt
2016-12-01 10:13                               ` [PING] " Dominik Vogt
2016-12-01 12:28                                 ` Bernd Schmidt
2016-12-02 12:36                                   ` Andreas Krebbel
2016-10-12 20:33                 ` [PATCH] Tweaks " David Malcolm
2016-10-13 10:24                   ` Bernd Schmidt
2016-10-13 14:08                     ` David Malcolm
2016-10-13 14:18                       ` Bernd Schmidt
2016-10-14 19:41                         ` [PATCH] (v2) " David Malcolm
2016-10-14 20:07                           ` Bernd Schmidt
2016-10-19 14:36             ` RTL frontend input format again (was Re: [PATCH 15/16] RTL frontend (rtl1), on top of dump reader) David Malcolm
2016-10-19 14:42               ` Bernd Schmidt
2016-10-19 17:19                 ` David Malcolm
2016-10-19 17:22                   ` Bernd Schmidt
2016-10-19 17:54                     ` David Malcolm
2016-10-20 13:55     ` INSN_UIDs " David Malcolm
2016-10-20 14:11       ` Bernd Schmidt
2016-10-20 14:20         ` David Malcolm
2016-10-20 14:22           ` Bernd Schmidt
2016-10-26 18:19         ` [PATCH] Show INSN_UIDs in compact mode David Malcolm
2016-10-26 18:20           ` Bernd Schmidt
2016-10-06 15:24   ` [PATCH 15/16] RTL frontend (rtl1), on top of dump reader Bernd Schmidt
2016-10-07 16:22     ` [PATCH] RTL frontend (rtl1), on top of dump reader (v4) David Malcolm
2016-10-05 15:45 ` [PATCH 14/16] RTL interpreter (work-in-progress) David Malcolm
2016-10-05 15:45 ` [PATCH 09/16] Split class rtx_reader into base_rtx_reader vs rtx_reader David Malcolm
2016-10-11 15:53   ` Bernd Schmidt
2016-10-18 20:30     ` David Malcolm
2016-10-19 14:45       ` Bernd Schmidt
2016-10-20 19:14         ` Richard Sandiford
2016-10-05 15:45 ` [PATCH 03/16] (approved) selftest.h: add temp_override fixture David Malcolm
2016-10-05 15:45 ` [PATCH 06/16] Introduce emit_status::ensure_regno_capacity David Malcolm
2016-10-05 15:55   ` Bernd Schmidt
2016-11-18 20:47     ` [PATCH] Introduce emit_status::ensure_regno_capacity (v5) David Malcolm
2016-11-22 13:34       ` Bernd Schmidt
2016-10-05 15:55   ` [PATCH 06/16] Introduce emit_status::ensure_regno_capacity Bernd Schmidt
2016-10-05 15:45 ` [PATCH 04/16] (approved) Expose forcibly_ggc_collect and run it after all selftests David Malcolm
2016-10-05 15:45 ` [PATCH 16/16] Add "__RTL" to cc1 David Malcolm
2016-10-05 16:10   ` Joseph Myers
2016-10-07 15:27     ` [PATCH] Add "__RTL" to cc1 (v2) David Malcolm
2016-10-13 13:49       ` Richard Biener
2016-10-13 13:52         ` Bernd Schmidt
2016-10-14  9:33           ` Richard Biener
2016-10-14  9:48             ` Bernd Schmidt
2016-10-14  9:50               ` Richard Biener
2016-10-14 19:25             ` David Malcolm
2016-10-14 19:27               ` Bernd Schmidt
2016-10-14 19:35                 ` David Malcolm
2016-10-14 19:23         ` David Malcolm

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).