public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 7/9] combine.c selftests
  2016-09-09  0:01 [PATCH 0/9] RFC: selftests based on RTL dumps David Malcolm
                   ` (4 preceding siblings ...)
  2016-09-09  0:01 ` [PATCH 3/9] selftest.h: add temp_override fixture David Malcolm
@ 2016-09-09  0:01 ` David Malcolm
  2016-09-16 20:45   ` Jeff Law
  2016-09-09  0:01 ` [PATCH 8/9] final.c selftests David Malcolm
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-09  0:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

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/combine.c            | 155 +++++++++++++++++++++++++++++++++++++++++++++++
 gcc/selftest-run-tests.c |   1 +
 gcc/selftest.h           |   1 +
 3 files changed, 157 insertions(+)

diff --git a/gcc/combine.c b/gcc/combine.c
index 1b262f9..9c148bb 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))
@@ -14441,3 +14445,154 @@ 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 char *dump_content, int dumped_first_pseudo_regno);
+
+ private:
+   dataflow_test m_df_test;
+};
+
+/* combine_test's constructor.  Write DUMP_CONTENT to a tempfile and load
+   it.  Initialize df and perform dataflow analysis.  */
+
+combine_test::combine_test (const char *dump_content,
+			    int dumped_first_pseudo_regno)
+: rtl_dump_test (dump_content, dumped_first_pseudo_regno),
+  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 ()
+{
+  /* 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.  */
+  const char *input_dump
+    = ("(insn 8 0 9 2 (set (reg:DI 78)\n"
+       "        (lshiftrt:DI (reg:DI 76)\n"
+       "            (const_int 32 [0x20])))\n"
+       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
+       "        641 {*aarch64_lshr_sisd_or_int_di3}\n"
+       "     (expr_list:REG_DEAD (reg:DI 76)\n"
+       "        (nil)))\n"
+       "(insn 9 8 0 2 (set (reg:SI 79)\n"
+       "        (ashiftrt:SI (subreg:SI (reg:DI 78) 0)\n"
+       "            (const_int 3 [0x3])))\n"
+       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
+       "        642 {*aarch64_ashr_sisd_or_int_si3}\n"
+       "     (expr_list:REG_DEAD (reg:DI 78)\n"
+       "        (nil)))\n");
+  combine_test t (input_dump, 76);
+
+  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 ()
+{
+  const char *input_dump
+    = ("(insn 8 0 9 2 (set (reg:DI 78)\n"
+       "        (lshiftrt:DI (reg:DI 76)\n"
+       "            (const_int 32 [0x20])))\n"
+       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
+       "        641 {*aarch64_lshr_sisd_or_int_di3}\n"
+       "     (expr_list:REG_DEAD (reg:DI 76)\n"
+       "        (nil)))\n"
+       "(insn 9 8 0 2 (set (reg:SI 79)\n"
+       "        (ashiftrt:SI (subreg:SI (reg:DI 80) 0)\n"
+       "            (const_int 3 [0x3])))\n"
+       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
+       "        642 {*aarch64_ashr_sisd_or_int_si3}\n"
+       "     (expr_list:REG_DEAD (reg:DI 78)\n"
+       "        (nil)))\n");
+  combine_test t (input_dump, 76);
+
+  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 14e5828..296fe00 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -68,6 +68,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 037a5ee..8b94c3a 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -190,6 +190,7 @@ extern void forcibly_ggc_collect ();
 /* 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 ();
-- 
1.8.5.3

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

* [PATCH 4/9] Expose forcibly_ggc_collect and run it after all selftests
  2016-09-09  0:01 [PATCH 0/9] RFC: selftests based on RTL dumps David Malcolm
  2016-09-09  0:01 ` [PATCH 6/9] df selftests David Malcolm
  2016-09-09  0:01 ` [PATCH 9/9] cse.c selftests David Malcolm
@ 2016-09-09  0:01 ` David Malcolm
  2016-09-16 20:30   ` Jeff Law
  2016-09-09  0:01 ` [PATCH 2/9] Add selftest::read_file David Malcolm
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-09  0:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

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.

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] 56+ messages in thread

* [PATCH 3/9] selftest.h: add temp_override fixture
  2016-09-09  0:01 [PATCH 0/9] RFC: selftests based on RTL dumps David Malcolm
                   ` (3 preceding siblings ...)
  2016-09-09  0:01 ` [PATCH 2/9] Add selftest::read_file David Malcolm
@ 2016-09-09  0:01 ` David Malcolm
  2016-09-14 22:24   ` Trevor Saunders
  2016-09-16 20:37   ` Jeff Law
  2016-09-09  0:01 ` [PATCH 7/9] combine.c selftests David Malcolm
                   ` (4 subsequent siblings)
  9 siblings, 2 replies; 56+ messages in thread
From: David Malcolm @ 2016-09-09  0:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

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] 56+ messages in thread

* [PATCH 9/9] cse.c selftests
  2016-09-09  0:01 [PATCH 0/9] RFC: selftests based on RTL dumps David Malcolm
  2016-09-09  0:01 ` [PATCH 6/9] df selftests David Malcolm
@ 2016-09-09  0:01 ` David Malcolm
  2016-09-16 20:34   ` Jeff Law
  2016-09-09  0:01 ` [PATCH 4/9] Expose forcibly_ggc_collect and run it after all selftests David Malcolm
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-09  0:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

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/cse.c                | 109 +++++++++++++++++++++++++++++++++++++++++++++++
 gcc/selftest-run-tests.c |   1 +
 gcc/selftest.h           |   1 +
 3 files changed, 111 insertions(+)

diff --git a/gcc/cse.c b/gcc/cse.c
index 0bfd7ff..f4f06fe 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,110 @@ 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
+
+  const char *input_dump
+    = (/* "r101 = r100 + 1;" */
+       "(insn 1 0 2 2 (set (reg:SI 101)\n"
+       "                   (plus:SI (reg:SI 100)\n"
+       "                            (const_int 1 [0x1]))) -1 (nil))\n"
+       /* "r102 = r100 + 1;" */
+       "(insn 2 1 3 2 (set (reg:SI 102)\n"
+       "                   (plus:SI (reg:SI 100)\n"
+       "                            (const_int 1 [0x1]))) -1 (nil))\n"
+       /* "*r103 = r101 * r102;" */
+       "(insn 3 2 0 2 (set (mem:SI (reg:SI 103) [1 i+0 S4 A32])\n"
+       "                   (mult:SI (reg:SI 101) (reg:SI 102))) -1 (nil))\n"
+       );
+  rtl_dump_test t (input_dump, 100);
+  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
+
+  /* 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.  */
+  const char *input_dump
+    = (";; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;\n"
+       "(insn 1045 0 1046 2 (set (reg:SI 480)\n"
+       "        (high:SI (symbol_ref:SI (\"isl_obj_map_vtable\") [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>))) y.c:12702 -1\n"
+       "     (nil))\n"
+       "(insn 1046 1045 1047 2 (set (reg/f:SI 479)\n"
+       "        (lo_sum:SI (reg:SI 480)\n"
+       "            (symbol_ref:SI (\"isl_obj_map_vtable\") [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>))) y.c:12702 -1\n"
+       "     (expr_list:REG_EQUAL (symbol_ref:SI (\"isl_obj_map_vtable\") [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)\n"
+       "        (nil)))\n"
+       "(insn 1047 1046 1048 2 (set (reg:DI 481)\n"
+       "        (subreg:DI (reg/f:SI 479) 0)) y.c:12702 -1\n"
+       "     (nil))\n"
+       "(insn 1048 1047 1049 2 (set (zero_extract:DI (reg/v:DI 191 [ obj1D.17368 ])\n"
+       "            (const_int 32 [0x20])\n"
+       "            (const_int 0 [0]))\n"
+       "        (reg:DI 481)) y.c:12702 -1\n"
+       "     (nil))\n"
+       /* 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])\n"
+       "                         (const_int 1 [0x1])) -1 (nil))\n");
+
+  rtl_dump_test t (input_dump);
+  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 015572c..5fdfb42 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -65,6 +65,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 6ad6c88..c0dc862 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -191,6 +191,7 @@ extern void forcibly_ggc_collect ();
    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 ();
-- 
1.8.5.3

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

* [PATCH 8/9] final.c selftests
  2016-09-09  0:01 [PATCH 0/9] RFC: selftests based on RTL dumps David Malcolm
                   ` (5 preceding siblings ...)
  2016-09-09  0:01 ` [PATCH 7/9] combine.c selftests David Malcolm
@ 2016-09-09  0:01 ` David Malcolm
  2016-09-16 21:12   ` Jeff Law
  2016-09-09  0:01 ` [PATCH 1/9] Introduce class rtx_reader David Malcolm
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-09  0:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

gcc/ChangeLog:
	* final.c: Include selftest.h and selftest-rtl.h.
	(class selftest::temp_asm_out): New subclass of
	selftest::named_temp_file.
	(selftest::temp_asm_out::temp_asm_out): New ctor.
	(selftest::temp_asm_out::~temp_asm_out): New dtor.
	(class selftest::asm_out_test): New subclass of
	selftest::rtl_dump_test.
	(selftest::asm_out_test::asm_out_test): New ctor.
	(selftest::test_jump_insn): New function.
	(selftest::test_empty_function): New function.
	(selftest::test_asm_for_insn): New function.
	(TEST_ASM_FOR_INSN): New macro.
	(selftest::test_x86_64_leal): New function.
	(selftest::test_x86_64_negl): New function.
	(selftest::test_x86_64_cmpl): New function.
	(selftest::test_x86_64_cmovge): New function.
	(selftest::test_x86_64_ret): New function.
	(selftest::final_c_tests): New function.
	* selftest-run-tests.c (selftest::run_tests): Call
	selftest::final_c_tests.
	* selftest.h (selftest::final_c_tests): New decl.
---
 gcc/final.c              | 271 +++++++++++++++++++++++++++++++++++++++++++++++
 gcc/selftest-run-tests.c |   1 +
 gcc/selftest.h           |   1 +
 3 files changed, 273 insertions(+)

diff --git a/gcc/final.c b/gcc/final.c
index eccc3d8..990f898 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -78,6 +78,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "rtl-iter.h"
 #include "print-rtl.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"		/* Needed for external data declarations.  */
@@ -4894,3 +4896,272 @@ get_call_reg_set_usage (rtx_insn *insn, HARD_REG_SET *reg_set,
   COPY_HARD_REG_SET (*reg_set, default_set);
   return false;
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Fixture for temporarily setting the global "asm_out_file"
+   to a named temporary file.  */
+
+class temp_asm_out : public named_temp_file
+{
+ public:
+  temp_asm_out (const location &loc);
+  ~temp_asm_out ();
+};
+
+/* Constructor.  Open a tempfile for writing and set "asm_out_file" to it.  */
+
+temp_asm_out::temp_asm_out (const location &loc)
+: named_temp_file (".s")
+{
+  gcc_assert (asm_out_file == NULL);
+  asm_out_file = fopen (get_filename (), "w");
+  if (!asm_out_file)
+    ::selftest::fail_formatted (loc, "unable to open tempfile: %s",
+				get_filename ());
+}
+
+/* Destructor.  Close the tempfile and unset "asm_out_file".
+   The tempfile is unlinked by the named_temp_file dtor.  */
+
+temp_asm_out::~temp_asm_out ()
+{
+  fclose (asm_out_file);
+  asm_out_file = NULL;
+}
+
+/* A subclass of rtl_dump_test for testing asm output.
+   Overrides asm_out_file to a tempfile, and temporarily
+   sets "reload_completed = 1;".  */
+
+class asm_out_test : public rtl_dump_test
+{
+ public:
+  asm_out_test (const location &loc, const char *dump_content);
+
+  /* Get the asm output written so far.  The caller should free
+     the returned ptr.  */
+  char *
+  get_output (const location &loc) const
+  {
+    fflush (asm_out_file);
+    return read_file (loc, m_asm_out.get_filename ());
+  }
+
+ private:
+  temp_asm_out m_asm_out;
+  temp_override <int> m_override_reload_completed;
+  temp_override <section *> m_override_in_section;
+};
+
+/* asm_out_test's constructor.  Write DUMP_CONTENT to a tempfile,
+   overrides "asm_out_file" to a tempfile, and temporarily
+   sets "reload_completed = 1;".
+   Assume that no pseudo regs are present in DUMP_CONTENT (by
+   using the default arg to rtl_dump_test's ctor).  */
+
+asm_out_test::asm_out_test (const location &loc, const char *dump_content)
+: rtl_dump_test (dump_content),
+  m_asm_out (loc),
+  /* Temporarily set reload_completed = true.
+     Needed e.g. by ix86_can_use_return_insn_p.  */
+  m_override_reload_completed (reload_completed, true),
+  /* Temporarily set "in_section = NULL;".  */
+  m_override_in_section (in_section, NULL)
+{
+}
+
+/* Test writing asm for a jump_insn.  */
+
+static void
+test_jump_insn ()
+{
+  const char *input_dump
+    = ("(jump_insn 1 0 2 4 (set (pc)\n"
+       "        (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1\n"
+       "     (nil)\n"
+       " -> 3)\n"
+       "(barrier 2 1 3)\n"
+       "(code_label 3 2 0 5 2 (nil) [1 uses])\n");
+  asm_out_test t (SELFTEST_LOCATION, input_dump);
+
+  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));
+
+  int seen;
+  final_scan_insn (jump_insn, stderr, 0, 0, &seen);
+
+  char *c = t.get_output (SELFTEST_LOCATION);
+  ASSERT_STREQ ("\tjmp\t.L2\n", c);
+  free (c);
+}
+
+/* Test writing asm for an empty function.  */
+
+static void
+test_empty_function ()
+{
+  /* Dump of the dump from cc1 in "test.c.289r.dwarf2" given this input:
+       void test_1 (void) {}
+     and compiling with -Os (for x86_64).  */
+  const char *dump
+    = (";; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)\n"
+       "(note 1 0 3 (nil) NOTE_INSN_DELETED)\n"
+       "(note 3 1 8 2 [bb 2] NOTE_INSN_BASIC_BLOCK)\n"
+       "(note 8 3 2 2 NOTE_INSN_PROLOGUE_END)\n"
+       "(note 2 8 9 2 NOTE_INSN_FUNCTION_BEG)\n"
+       "(note 9 2 10 2 NOTE_INSN_EPILOGUE_BEG)\n"
+       "(jump_insn:TI 10 9 11 2 (simple_return) test.c:3 697 {simple_return_internal}\n"
+       "     (nil)\n"
+       " -> simple_return)\n"
+       "(barrier 11 10 7)\n"
+       "(note 7 11 0 (nil) NOTE_INSN_DELETED)\n");
+
+  asm_out_test t (SELFTEST_LOCATION, dump);
+
+  shorten_branches (get_insns ());
+  rest_of_handle_final ();
+
+  /* Verify that some asm was written out.  */
+  char *c = t.get_output (SELFTEST_LOCATION);
+  if (0)
+    fprintf (stdout, "%s", c);
+  ASSERT_STR_CONTAINS (c, "\t.text\n");
+  ASSERT_STR_CONTAINS (c, "\n\t.type\ttest_1, @function\n");
+  ASSERT_STR_CONTAINS (c, "\ntest_1:\n");
+  ASSERT_STR_CONTAINS (c, "\n\t.cfi_startproc\n");
+  ASSERT_STR_CONTAINS (c, "\n\tret\n");
+  ASSERT_STR_CONTAINS (c, "\n\t.cfi_endproc\n");
+  ASSERT_STR_CONTAINS (c, "\n\t.size\ttest_1, .-test_1\n");
+  free (c);
+}
+
+/* Parse DUMP via an asm_out_test and run final_scan_insn on the first
+   insn seen in the dump.  Verify that the generated asm equals
+   EXPECTED_ASM.  Use LOC as the effective location when reporting any
+   errors.  */
+
+static void
+test_asm_for_insn (const location &loc, const char *dump,
+		   const char *expected_asm)
+{
+  asm_out_test t (loc, dump);
+
+  /* Locate the first insn in the dump.  */
+  rtx_insn *insn = get_insns ();
+
+  /* Write out asm for the insn.  */
+  int seen;
+  final_scan_insn (insn, stderr, 0, 0, &seen);
+
+  /* Verify that the expected asm was written out.  */
+  char *written_asm = t.get_output (loc);
+  ASSERT_STREQ_AT (loc, expected_asm, written_asm);
+  free (written_asm);
+}
+
+/* Parse DUMP via an asm_out_test and run final_scan_insn on the first
+   insn seen in the dump.  Verify that the generated asm equals
+   EXPECTED_ASM.  */
+
+#define TEST_ASM_FOR_INSN(DUMP, EXPECTED_ASM)			    \
+  SELFTEST_BEGIN_STMT							\
+    test_asm_for_insn (SELFTEST_LOCATION, (DUMP), (EXPECTED_ASM));	\
+  SELFTEST_END_STMT
+
+/* Various tests of how a particular instruction is recognized and
+   written out.  These all assume x86_64 and perhaps make additional
+   tuning assumptions.  */
+
+static void
+test_x86_64_leal ()
+{
+  TEST_ASM_FOR_INSN (
+    ("(insn:TI 31 0 0 2 (set (reg:SI 0 ax [93])\n"
+     "        (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])\n"
+     "            (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1\n"
+     "     (nil))\n"),
+    "\tleal\t4(%rdx), %eax\n");
+}
+
+static void
+test_x86_64_negl ()
+{
+  TEST_ASM_FOR_INSN (
+    ("(insn 27 0 0 2 (parallel [\n"
+     "            (set (reg:SI 1 dx [92])\n"
+     "                (neg:SI (reg/v:SI 1 dx [orig:90 k ] [90])))\n"
+     "            (clobber (reg:CC 17 flags))\n"
+     "        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1\n"
+     "     (expr_list:REG_UNUSED (reg:CC 17 flags)\n"
+     "        (nil)))\n"),
+    "\tnegl\t%edx\n");
+}
+
+static void
+test_x86_64_cmpl ()
+{
+  TEST_ASM_FOR_INSN (
+    ("(insn 28 0 0 2 (set (reg:CCGC 17 flags)\n"
+     "        (compare:CCGC (reg/v:SI 5 di [orig:88 i ] [88])\n"
+     "            (reg/v:SI 4 si [orig:89 j ] [89]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1\n"
+     "     (expr_list:REG_DEAD (reg/v:SI 5 di [orig:88 i ] [88])\n"
+     "        (expr_list:REG_DEAD (reg/v:SI 4 si [orig:89 j ] [89])\n"
+     "            (nil))))\n"),
+    "\tcmpl\t%esi, %edi\n");
+}
+
+static void
+test_x86_64_cmovge ()
+{
+  TEST_ASM_FOR_INSN (
+    ("(insn:TI 29 0 0 2 (set (reg:SI 0 ax [orig:87 <retval> ] [87])\n"
+     "        (if_then_else:SI (ge (reg:CCGC 17 flags)\n"
+     "                (const_int 0 [0]))\n"
+     "            (reg:SI 1 dx [92])\n"
+     "            (reg:SI 0 ax [93]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1\n"
+     "     (expr_list:REG_DEAD (reg:CCGC 17 flags)\n"
+     "        (expr_list:REG_DEAD (reg:SI 1 dx [92])\n"
+     "            (nil))))\n"),
+    "\tcmovge\t%edx, %eax\n");
+}
+
+static void
+test_x86_64_ret ()
+{
+  TEST_ASM_FOR_INSN (
+    ("(jump_insn:TI 34 0 0 2 (simple_return) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1\n"
+     "     (nil)\n"
+     " -> simple_return)\n"),
+    "\tret\n");
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+final_c_tests ()
+{
+  /* Only run these tests for i386.  */
+#ifndef I386_OPTS_H
+  return;
+#endif
+
+  test_jump_insn ();
+  test_empty_function ();
+  test_x86_64_leal ();
+  test_x86_64_negl ();
+  test_x86_64_cmpl ();
+  test_x86_64_cmovge ();
+  test_x86_64_ret ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 296fe00..015572c 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -76,6 +76,7 @@ selftest::run_tests ()
   spellcheck_c_tests ();
   spellcheck_tree_c_tests ();
   tree_cfg_c_tests ();
+  final_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 8b94c3a..6ad6c88 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -198,6 +198,7 @@ extern void edit_context_c_tests ();
 extern void et_forest_c_tests ();
 extern void fold_const_c_tests ();
 extern void fibonacci_heap_c_tests ();
+extern void final_c_tests ();
 extern void function_tests_c_tests ();
 extern void gimple_c_tests ();
 extern void ggc_tests_c_tests ();
-- 
1.8.5.3

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

* [PATCH 0/9] RFC: selftests based on RTL dumps
@ 2016-09-09  0:01 David Malcolm
  2016-09-09  0:01 ` [PATCH 6/9] df selftests David Malcolm
                   ` (9 more replies)
  0 siblings, 10 replies; 56+ messages in thread
From: David Malcolm @ 2016-09-09  0:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

The current selftest code is adequate for testing individual
instructions, but most interesting passes have logic involving the
interaction of multiple instructions, or require a CFG and function
to be runnable.  In theory we could write selftests by programatically
constructing a function and CFG "by hand" via API calls, but this is
awkward, tedious, and the resulting code is unnatural.  Examples can
be seen in function-tests.c; that file constructs trivial 3-block
functions, and is pushing the limits of what I'd want to write
"by hand".

This patch kit provides a more natural way to write RTL selftests,
by providing a parser for RTL dumps (or fragments of RTL dumps).  You
can copy and paste fragments of RTL dump into the source for a pass
and then have selftests that run part of the pass on that dump,
asserting that desired outcomes occur.

This is an updated and rewritten version of the RTL frontend work I
posted in May (c.f. "[PATCH 0/4] RFC: RTL frontend"
https://gcc.gnu.org/ml/gcc-patches/2016-05/msg00352.html).

In that patch kit, I introduced an rtl1 frontend, capable of parsing
RTL dumps, and running just one RTL pass on them, in the hope of
better testing individual RTL passes.

This patch kit takes a somewhat different approach: it provides
the infrastructure for parsing RTL dumps, but doesn't wire it up as
a frontend.  Instead, it just provides a set of classes for use when
writing selftests.  It would be possible to build out an "rtl1"
frontend as a followup to this kit.

The advantage of this approach is that it's possible to run and test
passes at finer granularity: for example, rather than being limited
to testing all of, say, pass "final", we can also write tests that
run just final_scan_insn on individual rtx_insn *, and verify that
the expected output is emitted.  Tests can be written at various
different levels, testing how the components of a pass handle fragments
of an insn, how they handle entire insns, basic blocks, and so on up
to running a whole pass on a whole function.

The disadvantage is that changing a selftest requires recompilation
of cc1 (though that drawback affects selftests in general).

An overview of the kit follows; patches 6-9 are probably the most
interesting, as they show example of the kinds of selftest that can
be written using this approach:

  * Patch 1 tidies up some global state in .md parsing, wrapping it up in
  an rtx_reader class.

  * Patches 2-4 add some selftest support code.

  * Patch 5 introduces a function_reader subclass of patch 1's rtx_reader,
  capable of parsing RTL function dumps (or fragments thereof), and
  generalizes things so that rtx parsing can be run from the host, rather
  than just at build time.

   * Patch 6 uses the infrastructure to write a dataflow selftest.  It's
   a trivial example, but hopefully shows how more interesting selftests
   could be written.  (it's much easier to write a selftest if a similar
   one already exists)

   * Patch 7 does the same, but for combine.c.

   * Patch 8 does the same, but for final.c, showing examples of both
   assembling an entire function, and of assembling individual rtx_insn *
   (to exercise the .md files and asm output code)

   * Patch 9 does the same, but for cse.c.  I attempted to create a
   selftest that directly reproduces PR 71779, though I haven't yet
   been able to to reproduce the issue (just load the insns and run cse
   on them).

These tests are very target-specific and were developed mostly for
target==x86_64, and a little for target==aarch64.
I put clauses like this in the various test functions, which is a kludge:

    /* Only run these tests for i386.  */
 #ifndef I386_OPTS_H
    return;
 #endif

Is there a better way to express this condition?  (I guess I could
add a selftest::target_is_x86_p () predicate).

Posting for comment (doesn't fully bootstrap yet due to a few stray
warnings).  Patches 1-4 could probably be applicable even without
the rest of the kit.

Thoughts?

David Malcolm (9):
  Introduce class rtx_reader
  Add selftest::read_file
  selftest.h: add temp_override fixture
  Expose forcibly_ggc_collect and run it after all selftests
  Introduce class function_reader
  df selftests
  combine.c selftests
  final.c selftests
  cse.c selftests

 gcc/Makefile.in          |    5 +
 gcc/cfgexpand.c          |    7 +-
 gcc/combine.c            |  155 ++++++
 gcc/cse.c                |  109 +++++
 gcc/df-core.c            |   77 +++
 gcc/emit-rtl.c           |   70 ++-
 gcc/emit-rtl.h           |    2 +
 gcc/errors.c             |   23 +-
 gcc/errors.h             |   13 +
 gcc/final.c              |  271 +++++++++++
 gcc/function-tests.c     |    2 +-
 gcc/function.c           |   41 +-
 gcc/function.h           |    4 +-
 gcc/genconstants.c       |    3 +-
 gcc/genenums.c           |    3 +-
 gcc/genmddeps.c          |    3 +-
 gcc/genpreds.c           |    9 +-
 gcc/gensupport.c         |   29 +-
 gcc/gensupport.h         |    6 +-
 gcc/ggc-tests.c          |   28 +-
 gcc/print-rtl.c          |    4 +-
 gcc/read-md.c            |  328 +++++++++----
 gcc/read-md.h            |  192 ++++++--
 gcc/read-rtl-function.c  | 1197 ++++++++++++++++++++++++++++++++++++++++++++++
 gcc/read-rtl-function.h  |   29 ++
 gcc/read-rtl.c           |  760 ++++++++++++++++++++++++++++-
 gcc/rtl.h                |    4 +
 gcc/selftest-rtl.c       |   81 ++++
 gcc/selftest-rtl.h       |   66 +++
 gcc/selftest-run-tests.c |   11 +
 gcc/selftest.c           |   60 +++
 gcc/selftest.h           |   46 ++
 gcc/tree-dfa.c           |    5 +
 33 files changed, 3410 insertions(+), 233 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

-- 
1.8.5.3

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

* [PATCH 2/9] Add selftest::read_file
  2016-09-09  0:01 [PATCH 0/9] RFC: selftests based on RTL dumps David Malcolm
                   ` (2 preceding siblings ...)
  2016-09-09  0:01 ` [PATCH 4/9] Expose forcibly_ggc_collect and run it after all selftests David Malcolm
@ 2016-09-09  0:01 ` David Malcolm
  2016-09-16 21:19   ` Jeff Law
  2016-09-09  0:01 ` [PATCH 3/9] selftest.h: add temp_override fixture David Malcolm
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-09  0:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

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] 56+ messages in thread

* [PATCH 6/9] df selftests
  2016-09-09  0:01 [PATCH 0/9] RFC: selftests based on RTL dumps David Malcolm
@ 2016-09-09  0:01 ` David Malcolm
  2016-09-16 20:40   ` Jeff Law
  2016-09-09  0:01 ` [PATCH 9/9] cse.c selftests David Malcolm
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-09  0:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

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/df-core.c            | 77 ++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/selftest-run-tests.c |  1 +
 gcc/selftest.h           |  1 +
 3 files changed, 79 insertions(+)

diff --git a/gcc/df-core.c b/gcc/df-core.c
index e531d58..cb8e2f9 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,78 @@ 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 ()
+{
+  const char *input_dump
+    = "(insn 1 0 0 2 (set (reg:SI 100) (reg:SI 101)) -1 (nil))\n";
+  rtl_dump_test t (input_dump, 100);
+  //print_rtl_with_bb (stdout, get_insns (), 1024);
+
+  dataflow_test dftest;
+
+  df_note_add_problem ();
+  df_analyze ();
+  //df_dump (stderr);
+  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 c90037c..14e5828 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -64,6 +64,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 75fea6f..037a5ee 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -190,6 +190,7 @@ extern void forcibly_ggc_collect ();
 /* 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 ();
-- 
1.8.5.3

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

* [PATCH 1/9] Introduce class rtx_reader
  2016-09-09  0:01 [PATCH 0/9] RFC: selftests based on RTL dumps David Malcolm
                   ` (6 preceding siblings ...)
  2016-09-09  0:01 ` [PATCH 8/9] final.c selftests David Malcolm
@ 2016-09-09  0:01 ` David Malcolm
  2016-09-16 22:15   ` Jeff Law
  2016-09-09  0:13 ` [PATCH 5/9] Introduce class function_reader David Malcolm
  2016-09-12 14:14 ` [PATCH 0/9] RFC: selftests based on RTL dumps Bernd Schmidt
  9 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-09  0:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

Bundle up various global variables within gensupport.c into a
class rtx_reader, with a view towards making it easier to run the
code more than once in-process.

gcc/ChangeLog:
	* genconstants.c (main): Introduce noop_reader and convert call
	to read_md_files to a method call.
	* genenums.c (main): Likewise.
	* genmddeps.c (main): Likewise.
	* genpreds.c (write_tm_constrs_h): Replace use of "in_fname" with
	rtx_reader_ptr->get_top_level_filename ().
	(write_tm_preds_h): Likewise.
	(write_insn_preds_c): Likewise.
	* gensupport.c (class gen_reader): New subclass of rtx_reader.
	(rtx_handle_directive): Convert to...
	(gen_reader::handle_unknown_directive): ...this.
	(init_rtx_reader_args_cb): Convert return type from bool to
	rtx_reader *.  Create a gen_reader instance, using it for the
	call to read_md_files.  Return it if no errors occur.
	(init_rtx_reader_args): Convert return type from bool to
	rtx_reader *.
	* gensupport.h (init_rtx_reader_args_cb): Likewise.
	(init_rtx_reader_args_cb): Likewise.
	* read-md.c (struct file_name_list): Move to class rtx_reader.
	(read_md_file): Delete in favor of rtx_reader::m_read_md_file.
	(read_md_filename): Delete in favor of
	rtx_reader::m_read_md_filename.
	(read_md_lineno): Delete in favor of rtx_reader::m_read_md_lineno.
	(in_fname): Delete in favor of rtx_reader::m_toplevel_fname.
	(base_dir): Delete in favor of rtx_reader::m_base_dir.
	(first_dir_md_include): Delete in favor of
	rtx_reader::m_first_dir_md_include.
	(last_dir_md_include_ptr): Delete in favor of
	rtx_reader::m_last_dir_md_include_ptr.
	(max_include_len): Delete.
	(rtx_reader_ptr): New.
	(fatal_with_file_and_line): Use get_filename and get_lineno
	accessors of rtx_reader_ptr.
	(require_char_ws): Likewise.
	(rtx_reader::read_char): New method, based on ::read_char.
	(rtx_reader::unread_char): New method, based on ::unread_char.
	(read_escape): Use get_filename and get_lineno accessors of
	rtx_reader_ptr.
	(read_braced_string): Use get_lineno accessor of rtx_reader_ptr.
	(read_string): Use get_filename and get_lineno accessors of
	rtx_reader_ptr.
	(rtx_reader::rtx_reader): New ctor.
	(rtx_reader::~rtx_reader): New dtor.
	(handle_include): Convert from a function to...
	(rtx_reader::handle_include): ...this method, converting
	handle_directive from a callback to a virtual function.
	(handle_file): Likewise, converting to...
	(rtx_reader::handle_file): ...this method.
	(handle_toplevel_file): Likewise, converting to...
	(rtx_reader::handle_toplevel_file): ...this method.
	(rtx_reader::get_current_location): New method.
	(parse_include): Convert from a function to...
	(rtx_reader::add_include_path): ...this method, dropping redundant
	update to unused max_include_len.
	(read_md_files): Convert from a function to...
	(rtx_reader::read_md_files): ...this method, converting
	handle_directive from a callback to a virtual function.
	(noop_reader::handle_unknown_directive): New method.
	* read-md.h (directive_handler_t): Delete this typedef.
	(in_fname): Delete.
	(read_md_file): Delete.
	(read_md_lineno): Delete.
	(read_md_filename): Delete.
	(class rtx_reader): New class.
	(rtx_reader_ptr): New decl.
	(class noop_reader): New subclass of rtx_reader.
	(read_char): Reimplement in terms of rtx_reader::read_char.
	(unread_char): Reimplement in terms of rtx_reader::unread_char.
	(read_md_files): Delete.
	* read-rtl.c (read_rtx_code): Update for deletion of globals
	read_md_filename and read_md_lineno.
---
 gcc/genconstants.c |   3 +-
 gcc/genenums.c     |   3 +-
 gcc/genmddeps.c    |   3 +-
 gcc/genpreds.c     |   9 ++-
 gcc/gensupport.c   |  29 +++++--
 gcc/gensupport.h   |   6 +-
 gcc/read-md.c      | 225 ++++++++++++++++++++++++++++++-----------------------
 gcc/read-md.h      |  98 ++++++++++++++++++-----
 gcc/read-rtl.c     |   3 +-
 9 files changed, 242 insertions(+), 137 deletions(-)

diff --git a/gcc/genconstants.c b/gcc/genconstants.c
index c10e3e3..e8be5b6 100644
--- a/gcc/genconstants.c
+++ b/gcc/genconstants.c
@@ -79,7 +79,8 @@ main (int argc, const char **argv)
 {
   progname = "genconstants";
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return (FATAL_EXIT_CODE);
 
   /* Initializing the MD reader has the side effect of loading up
diff --git a/gcc/genenums.c b/gcc/genenums.c
index db46a67..8af8d9a 100644
--- a/gcc/genenums.c
+++ b/gcc/genenums.c
@@ -49,7 +49,8 @@ main (int argc, const char **argv)
 {
   progname = "genenums";
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return (FATAL_EXIT_CODE);
 
   puts ("/* Generated automatically by the program `genenums'");
diff --git a/gcc/genmddeps.c b/gcc/genmddeps.c
index fd26a33..e3d229d 100644
--- a/gcc/genmddeps.c
+++ b/gcc/genmddeps.c
@@ -47,7 +47,8 @@ main (int argc, const char **argv)
   progname = "genmddeps";
   include_callback = add_filedep;
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return FATAL_EXIT_CODE;
 
   *last = NULL;
diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index 4c9dfc6..96f75bd 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -1204,7 +1204,8 @@ write_tm_constrs_h (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_CONSTRS_H\n\
@@ -1403,7 +1404,8 @@ write_tm_preds_h (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_PREDS_H\n\
@@ -1552,7 +1554,8 @@ write_insn_preds_c (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #include \"config.h\"\n\
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index 7e3aad3..3abb259b 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2228,10 +2228,18 @@ process_define_subst (void)
     }
 }
 \f
-/* A read_md_files callback for reading an rtx.  */
+/* A subclass of rtx_reader which reads .md files and calls process_rtx on
+   the top-level elements.  */
 
-static void
-rtx_handle_directive (file_location loc, const char *rtx_name)
+class gen_reader : public rtx_reader
+{
+ public:
+  gen_reader () : rtx_reader () {}
+  void handle_unknown_directive (file_location, const char *);
+};
+
+void
+gen_reader::handle_unknown_directive (file_location loc, const char *rtx_name)
 {
   auto_vec<rtx, 32> subrtxs;
   if (!read_rtx (rtx_name, &subrtxs))
@@ -2502,7 +2510,7 @@ check_define_attr_duplicates ()
 
 /* The entry point for initializing the reader.  */
 
-bool
+rtx_reader *
 init_rtx_reader_args_cb (int argc, const char **argv,
 			 bool (*parse_opt) (const char *))
 {
@@ -2518,7 +2526,8 @@ init_rtx_reader_args_cb (int argc, const char **argv,
   split_sequence_num = 1;
   peephole2_sequence_num = 1;
 
-  read_md_files (argc, argv, parse_opt, rtx_handle_directive);
+  gen_reader *reader = new gen_reader ();
+  reader->read_md_files (argc, argv, parse_opt);
 
   if (define_attr_queue != NULL)
     check_define_attr_duplicates ();
@@ -2534,12 +2543,18 @@ init_rtx_reader_args_cb (int argc, const char **argv,
   if (define_attr_queue != NULL)
     gen_mnemonic_attr ();
 
-  return !have_error;
+  if (have_error)
+    {
+      delete reader;
+      return NULL;
+    }
+
+  return reader;
 }
 
 /* Programs that don't have their own options can use this entry point
    instead.  */
-bool
+rtx_reader *
 init_rtx_reader_args (int argc, const char **argv)
 {
   return init_rtx_reader_args_cb (argc, argv, 0);
diff --git a/gcc/gensupport.h b/gcc/gensupport.h
index 645512c..618359d 100644
--- a/gcc/gensupport.h
+++ b/gcc/gensupport.h
@@ -125,9 +125,9 @@ struct optab_pattern
 };
 
 extern rtx add_implicit_parallel (rtvec);
-extern bool init_rtx_reader_args_cb (int, const char **,
-				     bool (*)(const char *));
-extern bool init_rtx_reader_args (int, const char **);
+extern rtx_reader *init_rtx_reader_args_cb (int, const char **,
+					    bool (*)(const char *));
+extern rtx_reader *init_rtx_reader_args (int, const char **);
 extern bool read_md_rtx (md_rtx_info *);
 extern unsigned int get_num_insn_codes ();
 
diff --git a/gcc/read-md.c b/gcc/read-md.c
index b422d8d..77e558c 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -31,12 +31,6 @@ struct ptr_loc {
   int lineno;
 };
 
-/* A singly-linked list of filenames.  */
-struct file_name_list {
-  struct file_name_list *next;
-  const char *fname;
-};
-
 /* Obstack used for allocating MD strings.  */
 struct obstack string_obstack;
 
@@ -56,34 +50,13 @@ static htab_t joined_conditions;
 /* An obstack for allocating joined_conditions entries.  */
 static struct obstack joined_conditions_obstack;
 
-/* The file we are reading.  */
-FILE *read_md_file;
-
-/* The filename of READ_MD_FILE.  */
-const char *read_md_filename;
-
-/* The current line number in READ_MD_FILE.  */
-int read_md_lineno;
-
-/* The name of the toplevel file that indirectly included READ_MD_FILE.  */
-const char *in_fname;
-
-/* The directory part of IN_FNAME.  NULL if IN_FNAME is a bare filename.  */
-static char *base_dir;
-
-/* The first directory to search.  */
-static struct file_name_list *first_dir_md_include;
-
-/* A pointer to the null terminator of the md include chain.  */
-static struct file_name_list **last_dir_md_include_ptr = &first_dir_md_include;
-
 /* 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 *);
 
-/* The current maximum length of directory names in the search path
-   for include files.  (Altered as we get more of them.)  */
-static size_t max_include_len;
+/* Global singleton.  */
+
+rtx_reader *rtx_reader_ptr;
 
 /* A table of md_constant structures, hashed by name.  Null if no
    constant expansion should occur.  */
@@ -92,8 +65,6 @@ static htab_t md_constants;
 /* A table of enum_type structures, hashed by name.  */
 static htab_t enum_types;
 
-static void handle_file (directive_handler_t);
-
 /* Given an object that starts with a char * name field, return a hash
    code for its name.  */
 
@@ -303,7 +274,8 @@ fatal_with_file_and_line (const char *msg, ...)
 
   va_start (ap, msg);
 
-  fprintf (stderr, "%s:%d: ", read_md_filename, read_md_lineno);
+  fprintf (stderr, "%s:%d: error: ", rtx_reader_ptr->get_filename (),
+	   rtx_reader_ptr->get_lineno ());
   vfprintf (stderr, msg, ap);
   putc ('\n', stderr);
 
@@ -322,8 +294,9 @@ fatal_with_file_and_line (const char *msg, ...)
     }
   context[i] = '\0';
 
-  fprintf (stderr, "%s:%d: following context is `%s'\n",
-	   read_md_filename, read_md_lineno, context);
+  fprintf (stderr, "%s:%d: note: following context is `%s'\n",
+	   rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+	   context);
 
   va_end (ap);
   exit (1);
@@ -402,6 +375,30 @@ require_char_ws (char expected)
     fatal_expected_char (expected, ch);
 }
 
+/* Read the next character from the file.  */
+
+int
+rtx_reader::read_char (void)
+{
+  int ch;
+
+  ch = getc (m_read_md_file);
+  if (ch == '\n')
+    m_read_md_lineno++;
+
+  return ch;
+}
+
+/* Put back CH, which was the last character read from the file.  */
+
+void
+rtx_reader::unread_char (int ch)
+{
+  if (ch == '\n')
+    m_read_md_lineno--;
+  ungetc (ch, m_read_md_file);
+}
+
 /* Read an rtx code name into NAME.  It is terminated by any of the
    punctuation chars of rtx printed syntax.  */
 
@@ -512,7 +509,8 @@ read_escape (void)
       /* pass anything else through, but issue a warning.  */
     default:
       fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
-	       read_md_filename, read_md_lineno, c);
+	       rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+	       c);
       obstack_1grow (&string_obstack, '\\');
       break;
     }
@@ -555,7 +553,7 @@ read_braced_string (void)
 {
   int c;
   int brace_depth = 1;  /* caller-processed */
-  unsigned long starting_read_md_lineno = read_md_lineno;
+  unsigned long starting_read_md_lineno = rtx_reader_ptr->get_lineno ();
 
   obstack_1grow (&string_obstack, '{');
   while (brace_depth)
@@ -601,7 +599,7 @@ read_string (int star_if_braced)
       c = read_skip_spaces ();
     }
 
-  old_lineno = read_md_lineno;
+  old_lineno = rtx_reader_ptr->get_lineno ();
   if (c == '"')
     stringbuf = read_quoted_string ();
   else if (c == '{')
@@ -616,7 +614,7 @@ read_string (int star_if_braced)
   if (saw_paren)
     require_char_ws (')');
 
-  set_md_ptr_loc (stringbuf, read_md_filename, old_lineno);
+  set_md_ptr_loc (stringbuf, rtx_reader_ptr->get_filename (), old_lineno);
   return stringbuf;
 }
 
@@ -901,13 +899,35 @@ traverse_enum_types (htab_trav callback, void *info)
   htab_traverse (enum_types, callback, info);
 }
 
+
+/* Constructor for rtx_reader.  */
+
+rtx_reader::rtx_reader ()
+: m_toplevel_fname (NULL),
+  m_read_md_filename (NULL),
+  m_read_md_lineno (0),
+  m_first_dir_md_include (NULL),
+  m_last_dir_md_include_ptr (&m_first_dir_md_include)
+{
+  /* Set the global singleton pointer.  */
+  rtx_reader_ptr = this;
+}
+
+/* rtx_reader's destructor.  */
+
+rtx_reader::~rtx_reader ()
+{
+  /* Clear the global singleton pointer.  */
+  rtx_reader_ptr = NULL;
+}
+
 /* Process an "include" directive, starting with the optional space
    after the "include".  Read in the file and use HANDLE_DIRECTIVE
    to process each unknown directive.  LINENO is the line number on
    which the "include" occurred.  */
 
-static void
-handle_include (file_location loc, directive_handler_t handle_directive)
+void
+rtx_reader::handle_include (file_location loc)
 {
   const char *filename;
   const char *old_filename;
@@ -924,7 +944,7 @@ handle_include (file_location loc, directive_handler_t handle_directive)
       struct file_name_list *stackp;
 
       /* Search the directory path, trying to open the file.  */
-      for (stackp = first_dir_md_include; stackp; stackp = stackp->next)
+      for (stackp = m_first_dir_md_include; stackp; stackp = stackp->next)
 	{
 	  static const char sep[2] = { DIR_SEPARATOR, '\0' };
 
@@ -940,8 +960,8 @@ handle_include (file_location loc, directive_handler_t handle_directive)
      filename with BASE_DIR.  */
   if (input_file == NULL)
     {
-      if (base_dir)
-	pathname = concat (base_dir, filename, NULL);
+      if (m_base_dir)
+	pathname = concat (m_base_dir, filename, NULL);
       else
 	pathname = xstrdup (filename);
       input_file = fopen (pathname, "r");
@@ -957,21 +977,22 @@ handle_include (file_location loc, directive_handler_t handle_directive)
   /* Save the old cursor.  Note that the LINENO argument to this
      function is the beginning of the include statement, while
      read_md_lineno has already been advanced.  */
-  old_file = read_md_file;
-  old_filename = read_md_filename;
-  old_lineno = read_md_lineno;
+  old_file = m_read_md_file;
+  old_filename = m_read_md_filename;
+  old_lineno = m_read_md_lineno;
 
   if (include_callback)
     include_callback (pathname);
 
-  read_md_file = input_file;
-  read_md_filename = pathname;
-  handle_file (handle_directive);
+  m_read_md_file = input_file;
+  m_read_md_filename = pathname;
+
+  handle_file ();
 
   /* Restore the old cursor.  */
-  read_md_file = old_file;
-  read_md_filename = old_filename;
-  read_md_lineno = old_lineno;
+  m_read_md_file = old_file;
+  m_read_md_filename = old_filename;
+  m_read_md_lineno = old_lineno;
 
   /* Do not free the pathname.  It is attached to the various rtx
      queue elements.  */
@@ -981,16 +1002,16 @@ handle_include (file_location loc, directive_handler_t handle_directive)
    read_md_filename are valid.  Use HANDLE_DIRECTIVE to handle
    unknown directives.  */
 
-static void
-handle_file (directive_handler_t handle_directive)
+void
+rtx_reader::handle_file ()
 {
   struct md_name directive;
   int c;
 
-  read_md_lineno = 1;
+  m_read_md_lineno = 1;
   while ((c = read_skip_spaces ()) != EOF)
     {
-      file_location loc (read_md_filename, read_md_lineno);
+      file_location loc = get_current_location ();
       if (c != '(')
 	fatal_expected_char ('(', c);
 
@@ -1002,49 +1023,51 @@ handle_file (directive_handler_t handle_directive)
       else if (strcmp (directive.string, "define_c_enum") == 0)
 	handle_enum (loc, false);
       else if (strcmp (directive.string, "include") == 0)
-	handle_include (loc, handle_directive);
-      else if (handle_directive)
-	handle_directive (loc, directive.string);
+	handle_include (loc);
       else
-	read_skip_construct (1, loc);
+	handle_unknown_directive (loc, directive.string);
 
       require_char_ws (')');
     }
-  fclose (read_md_file);
+  fclose (m_read_md_file);
 }
 
-/* Like handle_file, but for top-level files.  Set up in_fname and
-   base_dir accordingly.  */
+/* Like handle_file, but for top-level files.  Set up m_toplevel_fname
+   and m_base_dir accordingly.  */
 
-static void
-handle_toplevel_file (directive_handler_t handle_directive)
+void
+rtx_reader::handle_toplevel_file ()
 {
   const char *base;
 
-  in_fname = read_md_filename;
-  base = lbasename (in_fname);
-  if (base == in_fname)
-    base_dir = NULL;
+  m_toplevel_fname = m_read_md_filename;
+  base = lbasename (m_toplevel_fname);
+  if (base == m_toplevel_fname)
+    m_base_dir = NULL;
   else
-    base_dir = xstrndup (in_fname, base - in_fname);
+    m_base_dir = xstrndup (m_toplevel_fname, base - m_toplevel_fname);
+
+  handle_file ();
+}
 
-  handle_file (handle_directive);
+file_location
+rtx_reader::get_current_location () const
+{
+  return file_location (m_read_md_filename, m_read_md_lineno);
 }
 
 /* Parse a -I option with argument ARG.  */
 
-static void
-parse_include (const char *arg)
+void
+rtx_reader::add_include_path (const char *arg)
 {
   struct file_name_list *dirtmp;
 
   dirtmp = XNEW (struct file_name_list);
   dirtmp->next = 0;
   dirtmp->fname = arg;
-  *last_dir_md_include_ptr = dirtmp;
-  last_dir_md_include_ptr = &dirtmp->next;
-  if (strlen (dirtmp->fname) > max_include_len)
-    max_include_len = strlen (dirtmp->fname);
+  *m_last_dir_md_include_ptr = dirtmp;
+  m_last_dir_md_include_ptr = &dirtmp->next;
 }
 
 /* The main routine for reading .md files.  Try to process all the .md
@@ -1054,16 +1077,11 @@ parse_include (const char *arg)
 
    PARSE_OPT, if nonnull, is passed all unknown command-line arguments.
    It should return true if it recognizes the argument or false if a
-   generic error should be reported.
-
-   If HANDLE_DIRECTIVE is nonnull, the parser calls it for each
-   unknown directive, otherwise it just skips such directives.
-   See the comment above the directive_handler_t definition for
-   details about the callback's interface.  */
+   generic error should be reported.  */
 
 bool
-read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
-	       directive_handler_t handle_directive)
+rtx_reader::read_md_files (int argc, const char **argv,
+			   bool (*parse_opt) (const char *))
 {
   int i;
   bool no_more_options;
@@ -1101,9 +1119,9 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 	if (argv[i][1] == 'I')
 	  {
 	    if (argv[i][2] != '\0')
-	      parse_include (argv[i] + 2);
+	      add_include_path (argv[i] + 2);
 	    else if (++i < argc)
-	      parse_include (argv[i]);
+	      add_include_path (argv[i]);
 	    else
 	      fatal ("directory name missing after -I option");
 	    continue;
@@ -1131,9 +1149,9 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 	      if (already_read_stdin)
 		fatal ("cannot read standard input twice");
 
-	      read_md_file = stdin;
-	      read_md_filename = "<stdin>";
-	      handle_toplevel_file (handle_directive);
+	      m_read_md_file = stdin;
+	      m_read_md_filename = "<stdin>";
+	      handle_toplevel_file ();
 	      already_read_stdin = true;
 	      continue;
 	    }
@@ -1149,14 +1167,14 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 
       /* If we get here we are looking at a non-option argument, i.e.
 	 a file to be processed.  */
-      read_md_filename = argv[i];
-      read_md_file = fopen (read_md_filename, "r");
-      if (read_md_file == 0)
+      m_read_md_filename = argv[i];
+      m_read_md_file = fopen (m_read_md_filename, "r");
+      if (m_read_md_file == 0)
 	{
-	  perror (read_md_filename);
+	  perror (m_read_md_filename);
 	  return false;
 	}
-      handle_toplevel_file (handle_directive);
+      handle_toplevel_file ();
       num_files++;
     }
 
@@ -1164,10 +1182,19 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
      read the standard input now.  */
   if (num_files == 0 && !already_read_stdin)
     {
-      read_md_file = stdin;
-      read_md_filename = "<stdin>";
-      handle_toplevel_file (handle_directive);
+      m_read_md_file = stdin;
+      m_read_md_filename = "<stdin>";
+      handle_toplevel_file ();
     }
 
   return !have_error;
 }
+
+/* class noop_reader : public rtx_reader */
+
+/* A dummy implementation which skips unknown directives.  */
+void
+noop_reader::handle_unknown_directive (file_location loc, const char *)
+{
+  read_skip_construct (1, loc);
+}
diff --git a/gcc/read-md.h b/gcc/read-md.h
index fa25951..82a628b 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -90,16 +90,81 @@ struct enum_type {
   unsigned int num_values;
 };
 
-/* A callback that handles a single .md-file directive, up to but not
-   including the closing ')'.  It takes two arguments: the file position
-   at which the directive started, and the name of the directive.  The next
-   unread character is the optional space after the directive name.  */
-typedef void (*directive_handler_t) (file_location, const char *);
-
-extern const char *in_fname;
-extern FILE *read_md_file;
-extern int read_md_lineno;
-extern const char *read_md_filename;
+class rtx_reader
+{
+ public:
+  rtx_reader ();
+  virtual ~rtx_reader ();
+
+  bool read_md_files (int, const char **, bool (*) (const char *));
+
+  /* A hook that handles a single .md-file directive, up to but not
+     including the closing ')'.  It takes two arguments: the file position
+     at which the directive started, and the name of the directive.  The next
+     unread character is the optional space after the directive name.  */
+  virtual void handle_unknown_directive (file_location, const char *) = 0;
+
+  file_location get_current_location () const;
+
+  int read_char (void);
+  void unread_char (int ch);
+
+  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; }
+
+ private:
+  /* A singly-linked list of filenames.  */
+  struct file_name_list {
+    struct file_name_list *next;
+    const char *fname;
+  };
+
+ private:
+  void handle_file ();
+  void handle_toplevel_file ();
+  void handle_include (file_location loc);
+  void add_include_path (const char *arg);
+
+ private:
+  /* The name of the toplevel file that indirectly included
+     m_read_md_file.  */
+  const char *m_toplevel_fname;
+
+  /* The directory part of m_toplevel_fname
+     NULL if m_toplevel_fname is a bare filename.  */
+  char *m_base_dir;
+
+  /* The file we are reading.  */
+  FILE *m_read_md_file;
+
+  /* The filename of m_read_md_file.  */
+  const char *m_read_md_filename;
+
+  /* The current line number in m_read_md_file.  */
+  int m_read_md_lineno;
+
+  /* The first directory to search.  */
+  file_name_list *m_first_dir_md_include;
+
+  /* A pointer to the null terminator of the md include chain.  */
+  file_name_list **m_last_dir_md_include_ptr;
+};
+
+/* Global singleton.  */
+extern rtx_reader *rtx_reader_ptr;
+
+/* An rtx_reader subclass which skips unknown directives.  */
+
+class noop_reader : public rtx_reader
+{
+ public:
+  noop_reader () : rtx_reader () {}
+
+  /* A dummy implementation which skips unknown directives.  */
+  void handle_unknown_directive (file_location, const char *);
+};
+
 extern struct obstack string_obstack;
 extern void (*include_callback) (const char *);
 
@@ -108,12 +173,7 @@ extern void (*include_callback) (const char *);
 static inline int
 read_char (void)
 {
-  int ch;
-
-  ch = getc (read_md_file);
-  if (ch == '\n')
-    read_md_lineno++;
-  return ch;
+  return rtx_reader_ptr->read_char ();
 }
 
 /* Put back CH, which was the last character read from the MD file.  */
@@ -121,9 +181,7 @@ read_char (void)
 static inline void
 unread_char (int ch)
 {
-  if (ch == '\n')
-    read_md_lineno--;
-  ungetc (ch, read_md_file);
+  rtx_reader_ptr->unread_char (ch);
 }
 
 extern hashval_t leading_string_hash (const void *);
@@ -151,7 +209,5 @@ 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 *);
-extern bool read_md_files (int, const char **, bool (*) (const char *),
-			   directive_handler_t);
 
 #endif /* GCC_READ_MD_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 4614e35..eda9382 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -1234,6 +1234,7 @@ read_rtx_code (const char *code_name)
 		  || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
 	    {
 	      char line_name[20];
+	      const char *read_md_filename = rtx_reader_ptr->get_filename ();
 	      const char *fn = (read_md_filename ? read_md_filename : "rtx");
 	      const char *slash;
 	      for (slash = fn; *slash; slash ++)
@@ -1241,7 +1242,7 @@ read_rtx_code (const char *code_name)
 		  fn = slash + 1;
 	      obstack_1grow (&string_obstack, '*');
 	      obstack_grow (&string_obstack, fn, strlen (fn));
-	      sprintf (line_name, ":%d", read_md_lineno);
+	      sprintf (line_name, ":%d", rtx_reader_ptr->get_lineno ());
 	      obstack_grow (&string_obstack, line_name, strlen (line_name)+1);
 	      stringbuf = XOBFINISH (&string_obstack, char *);
 	    }
-- 
1.8.5.3

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

* [PATCH 5/9] Introduce class function_reader
  2016-09-09  0:01 [PATCH 0/9] RFC: selftests based on RTL dumps David Malcolm
                   ` (7 preceding siblings ...)
  2016-09-09  0:01 ` [PATCH 1/9] Introduce class rtx_reader David Malcolm
@ 2016-09-09  0:13 ` David Malcolm
  2016-09-16 21:31   ` Jeff Law
  2016-09-12 14:14 ` [PATCH 0/9] RFC: selftests based on RTL dumps Bernd Schmidt
  9 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-09  0:13 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

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.
	* cfgexpand.c (pass_expand::execute): Move stack initializations
	to rtl_data::init_stack_alignment and call it.  Pass "true"
	for new "emit_insns" param of expand_function_start.
	* 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.
	(rtl_data::init_stack_alignment): New method.
	(get_insn_by_uid): New function.
	* emit-rtl.h (rtl_data::init_stack_alignment): New method.
	* 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)).
	(expand_function_start): Add param "emit_insns", and use it to
	guard the various gen/emit calls.
	* function.h (emit_status::ensure_regno_capacity): New method.
	(expand_function_start): Add bool param to decl.
	* gensupport.c (gen_reader::gen_reader): Add NULL for new policy
	param of rtx_reader ctor.
	* 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 '/'.
	(require_char): New function.
	(require_word_ws): New function.
	(peek_char): New function.
	(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.  */
	(rtx_reader::rtx_reader): Add rtl_reader_policy * param, using
	it to initialize m_policy.
	(rtx_reader::~rtx_reader): Free m_base_dir.  Clean up global data.
	* read-md.h (struct file_location): Move to errors.h.
	(file_location::file_location): Likewise.
	Include errors.h.
	(class regno_remapper): New class.
	(struct rtl_reader_policy): New struct.
	(rtx_reader::rtx_reader): Add rtl_reader_policy * param.
	(rtx_reader::add_fixup_insn_uid): New vfunc.
	(rtx_reader::add_fixup_bb): New vfunc.
	(rtx_reader::add_fixup_note_insn_basic_block): New vfunc.
	(rtx_reader::add_fixup_source_location): New vfunc.
	(rtx_reader::add_fixup_jump_label): New vfunc.
	(rtx_reader::add_fixup_expr): New vfunc.
	(rtx_reader::remap_regno): New method.
	(rtx_reader::m_policy): New field.
	(noop_reader::noop_reader): Add NULL for new policy param of
	rtx_reader ctor.
	(peek_char): New decl.
	(require_char): New decl.
	(require_word_ws): New decl.
	(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.
	(read_rtx): Likewise.  Move one-time initialization logic to...
	(one_time_initialization): New function.
	(parse_reg_note_name): New function.
	(parse_note_insn_name): New function.
	(maybe_read_location): New function.
	(read_until): New function.
	(strip_trailing_whitespace): New function.
	(read_flags): New function.
	(regno_remapper::get_effective_regno): New method.
	(rtx_reader::remap_regno): New method.
	(read_rtx_code): Remove "static".  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 SYMBOL_REF data, REG_NOTE names,
	INSN_UID values, note-specific data, basic block IDs,
	jump labels, hexdump values of wide ints, REG_EXPR, MEM_EXPR,
	skipping recognized insn names, remapping register numbers.
	When on host, reallocate XSTR and XTMPL fields in the GC-managed
	heap.
	(lookup_global_register): New function.
	(consolidate_reg): New function.
	(consolidate_singletons): New function.
	(read_nested_rtx): Call consolidate_singletons.
	* rtl.h (read_rtx): Wrap decl with #ifdef GENERATOR_FILE.
	(read_rtx_code): New decl.
	* 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/Makefile.in          |    5 +
 gcc/cfgexpand.c          |    7 +-
 gcc/emit-rtl.c           |   70 ++-
 gcc/emit-rtl.h           |    2 +
 gcc/errors.c             |   23 +-
 gcc/errors.h             |   13 +
 gcc/function-tests.c     |    2 +-
 gcc/function.c           |   41 +-
 gcc/function.h           |    4 +-
 gcc/gensupport.c         |    2 +-
 gcc/print-rtl.c          |    4 +-
 gcc/read-md.c            |  109 ++++-
 gcc/read-md.h            |  100 +++-
 gcc/read-rtl-function.c  | 1197 ++++++++++++++++++++++++++++++++++++++++++++++
 gcc/read-rtl-function.h  |   29 ++
 gcc/read-rtl.c           |  757 ++++++++++++++++++++++++++++-
 gcc/rtl.h                |    4 +
 gcc/selftest-rtl.c       |   81 ++++
 gcc/selftest-rtl.h       |   66 +++
 gcc/selftest-run-tests.c |    1 +
 gcc/selftest.h           |    1 +
 gcc/tree-dfa.c           |    5 +
 22 files changed, 2434 insertions(+), 89 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

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7c18285..341c188 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1265,6 +1265,7 @@ OBJS = \
 	dwarf2cfi.o \
 	dwarf2out.o \
 	emit-rtl.o \
+	errors.o \
 	et-forest.o \
 	except.o \
 	explow.o \
@@ -1401,6 +1402,9 @@ OBJS = \
 	print-rtl.o \
 	print-tree.o \
 	profile.o \
+	read-md.o \
+	read-rtl.o \
+	read-rtl-function.o \
 	real.o \
 	realmpfr.o \
 	recog.o \
@@ -1428,6 +1432,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/cfgexpand.c b/gcc/cfgexpand.c
index 130a16b..f97e1fd 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -6219,10 +6219,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
@@ -6254,7 +6251,7 @@ pass_expand::execute (function *fun)
     }
 
   /* Set up parameters and prepare for return, for the function.  */
-  expand_function_start (current_function_decl);
+  expand_function_start (current_function_decl, true);
 
   /* If we emitted any instructions for setting up the variables,
      emit them before the FUNCTION_START note.  */
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index a724608..4fdf708 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;
+}
 
-      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 < NEW_SIZE.  */
 
-      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 new_size)
+{
+  if (new_size < regno_pointer_align_length)
+    return;
 
-      crtl->emit.regno_pointer_align_length = old_size * 2;
-    }
+  int old_size = regno_pointer_align_length;
 
-  val = gen_raw_REG (mode, reg_rtx_no);
-  regno_reg_rtx[reg_rtx_no++] = val;
-  return val;
+  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.  */
@@ -5686,7 +5692,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,
@@ -6304,5 +6311,30 @@ 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;
+}
+
+/* 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;
+}
+
 \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;
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..c63f06b 100644
--- a/gcc/errors.h
+++ b/gcc/errors.h
@@ -28,8 +28,21 @@ 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);
+
+  const char *filename;
+  int lineno;
+};
+
+inline file_location::file_location (const char *filename_in, int lineno_in)
+  : filename (filename_in), lineno (lineno_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 53bad87..fe9a07d 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))
@@ -5087,10 +5088,12 @@ stack_protect_epilogue (void)
    emitting RTL.
    SUBR is the FUNCTION_DECL node.
    PARMS_HAVE_CLEANUPS is nonzero if there are cleanups associated with
-   the function's parameters, which must be run at any return statement.  */
+   the function's parameters, which must be run at any return statement.
+   EMIT_INSNS is true if instructions are to emitted, false to avoid this
+   (for use when loading RTL function dumps).  */
 
 void
-expand_function_start (tree subr)
+expand_function_start (tree subr, bool emit_insns)
 {
   /* Make sure volatile mem refs aren't considered
      valid operands of arithmetic insns.  */
@@ -5106,7 +5109,8 @@ expand_function_start (tree subr)
   /* Make the label for return statements to jump to.  Do not special
      case machines with special return instructions -- they will be
      handled later during jump, ifcvt, or epilogue creation.  */
-  return_label = gen_label_rtx ();
+  if (emit_insns)
+    return_label = gen_label_rtx ();
 
   /* Initialize rtx used to return the value.  */
   /* Do this before assign_parms so that we copy the struct value address
@@ -5132,7 +5136,7 @@ expand_function_start (tree subr)
 	  /* Expect to be passed the address of a place to store the value.
 	     If it is passed as an argument, assign_parms will take care of
 	     it.  */
-	  if (sv)
+	  if (sv && emit_insns)
 	    {
 	      value_address = gen_reg_rtx (Pmode);
 	      emit_move_insn (value_address, sv);
@@ -5209,7 +5213,7 @@ expand_function_start (tree subr)
   assign_parms (subr);
 
   /* If function gets a static chain arg, store it.  */
-  if (cfun->static_chain_decl)
+  if (cfun->static_chain_decl && emit_insns)
     {
       tree parm = cfun->static_chain_decl;
       rtx local, chain;
@@ -5253,7 +5257,7 @@ expand_function_start (tree subr)
 
   /* If the function receives a non-local goto, then store the
      bits we need to restore the frame pointer.  */
-  if (cfun->nonlocal_goto_save_area)
+  if (cfun->nonlocal_goto_save_area && emit_insns)
     {
       tree t_save;
       rtx r_save;
@@ -5276,22 +5280,25 @@ expand_function_start (tree subr)
      The move is supposed to make sdb output more accurate.  */
   /* Indicate the beginning of the function body,
      as opposed to parm setup.  */
-  emit_note (NOTE_INSN_FUNCTION_BEG);
+  if (emit_insns)
+    {
+      emit_note (NOTE_INSN_FUNCTION_BEG);
 
-  gcc_assert (NOTE_P (get_last_insn ()));
+      gcc_assert (NOTE_P (get_last_insn ()));
 
-  parm_birth_insn = get_last_insn ();
+      parm_birth_insn = get_last_insn ();
 
-  if (crtl->profile)
-    {
+      if (crtl->profile)
+	{
 #ifdef PROFILE_HOOK
-      PROFILE_HOOK (current_function_funcdef_no);
+	  PROFILE_HOOK (current_function_funcdef_no);
 #endif
-    }
+	}
 
-  /* If we are doing generic stack checking, the probe should go here.  */
-  if (flag_stack_check == GENERIC_STACK_CHECK)
-    stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
+      /* If we are doing generic stack checking, the probe should go here.  */
+      if (flag_stack_check == GENERIC_STACK_CHECK)
+	stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
+    }
 }
 \f
 void
diff --git a/gcc/function.h b/gcc/function.h
index 590a490..40aa910 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;
@@ -619,7 +621,7 @@ extern void pop_dummy_function (void);
 extern void init_dummy_function_start (void);
 extern void init_function_start (tree);
 extern void stack_protect_epilogue (void);
-extern void expand_function_start (tree);
+extern void expand_function_start (tree, bool);
 extern void expand_dummy_function_end (void);
 
 extern void thread_prologue_and_epilogue_insns (void);
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index 3abb259b..378e0bf 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2234,7 +2234,7 @@ process_define_subst (void)
 class gen_reader : public rtx_reader
 {
  public:
-  gen_reader () : rtx_reader () {}
+  gen_reader () : rtx_reader (NULL) {}
   void handle_unknown_directive (file_location, const char *);
 };
 
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 77e558c..217ff49 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.  */
 
@@ -345,7 +347,7 @@ read_skip_spaces (void)
 	    if (c != '*')
 	      {
 		unread_char (c);
-		fatal_with_file_and_line ("stray '/' in file");
+		return '/';
 	      }
 
 	    prevc = 0;
@@ -364,6 +366,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 +387,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
@@ -399,11 +422,21 @@ 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.  */
 
-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;
@@ -441,8 +474,12 @@ read_name (struct md_name *name)
       c = read_char ();
     }
 
+  unread_char (c);
+  *out_loc = 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;
@@ -463,6 +500,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 = 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.
@@ -608,6 +675,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);
 
@@ -902,12 +977,13 @@ traverse_enum_types (htab_trav callback, void *info)
 
 /* Constructor for rtx_reader.  */
 
-rtx_reader::rtx_reader ()
+rtx_reader::rtx_reader (rtl_reader_policy *policy)
 : m_toplevel_fname (NULL),
   m_read_md_filename (NULL),
   m_read_md_lineno (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_policy (policy)
 {
   /* Set the global singleton pointer.  */
   rtx_reader_ptr = this;
@@ -917,6 +993,27 @@ rtx_reader::rtx_reader ()
 
 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;
 }
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 82a628b..33d33c4 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -21,18 +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);
-
-  const char *filename;
-  int lineno;
-};
-
-inline file_location::file_location (const char *filename_in, int lineno_in)
-  : filename (filename_in), lineno (lineno_in) {}
+#include "errors.h"
 
 /* Holds one symbol or number in the .md file.  */
 struct md_name {
@@ -90,10 +79,41 @@ struct enum_type {
   unsigned int num_values;
 };
 
+/* A class for remapping register numbers in dumpfiles to
+   equivalent register numbers for the current target.  */
+
+class regno_remapper
+{
+ public:
+  /* Zero means "do nothing", otherwise DUMPED_FIRST_PSEUDO_REGNO
+     is the lowest numbered pseudo-reg seen in the dumpfile.  */
+  regno_remapper (int dumped_first_pseudo_regno)
+    : m_dumped_first_pseudo_regno (dumped_first_pseudo_regno) {}
+
+  unsigned int get_effective_regno (int dumped_regno) const;
+
+ private:
+  int m_dumped_first_pseudo_regno;
+};
+
+/* An optional policy class for class rtx_reader.  */
+
+struct rtl_reader_policy
+{
+  rtl_reader_policy (regno_remapper *regno_remapper_)
+  : m_regno_remapper (regno_remapper_)
+  {
+  }
+
+  regno_remapper *m_regno_remapper;
+};
+
+/* A class for reading .md files and RTL dump files.  */
+
 class rtx_reader
 {
  public:
-  rtx_reader ();
+  rtx_reader (rtl_reader_policy *policy);
   virtual ~rtx_reader ();
 
   bool read_md_files (int, const char **, bool (*) (const char *));
@@ -104,6 +124,47 @@ class rtx_reader
      unread character is the optional space after the directive name.  */
   virtual void handle_unknown_directive (file_location, const char *) = 0;
 
+  /* A hook for the RTL function dump reader to override, to record insn UIDs
+     for later fixup.  */
+  virtual void add_fixup_insn_uid (file_location /*loc*/, rtx /*insn*/,
+				   int /*operand_idx*/, int /*insn_uid*/)
+  {}
+
+  /* A hook for the RTL function dump reader to override, to record
+     basic block IDs for later fixup.  */
+  virtual void add_fixup_bb (file_location /*loc*/, rtx /*insn*/,
+			     int /*operand_idx*/, int /*bb_idx*/)
+  {}
+
+  /* A hook for the RTL function dump reader to override, to record
+     basic block IDs for fixup of NOTE_INSN_BASIC_BLOCK.  */
+  virtual void add_fixup_note_insn_basic_block (file_location /*loc*/,
+						rtx /*insn*/,
+						int /*operand_idx*/,
+						int /*bb_idx*/)
+  {}
+
+  /* A hook for the RTL function dump reader to override, to record
+     source location information for fixing up into location_t values. */
+  virtual void add_fixup_source_location (file_location /*loc*/, rtx /*insn*/,
+					  int /*operand_idx*/,
+					  const char */*filename*/,
+					  int /*lineno*/)
+  {}
+
+  /* A hook for the RTL function dump reader to override, to record
+     label names for fixing up the JUMP_LABEL of an insn.  */
+  virtual void add_fixup_jump_label (file_location /*loc*/, rtx /*insn*/,
+				     int /*operand_idx*/,
+				     const char */*label*/)
+  {}
+
+  /* A hook for the RTL function dump reader to override, to record
+     textual tree dumps for fix up the expr of an rtx (REG or MEM).  */
+  virtual void add_fixup_expr (file_location /*loc*/, rtx /*x*/,
+			       const char */*desc*/)
+  {}
+
   file_location get_current_location () const;
 
   int read_char (void);
@@ -113,6 +174,8 @@ class rtx_reader
   const char *get_filename () const { return m_read_md_filename; }
   int get_lineno () const { return m_read_md_lineno; }
 
+  int remap_regno (int dumped_regno) const;
+
  private:
   /* A singly-linked list of filenames.  */
   struct file_name_list {
@@ -149,6 +212,8 @@ class rtx_reader
 
   /* A pointer to the null terminator of the md include chain.  */
   file_name_list **m_last_dir_md_include_ptr;
+
+  rtl_reader_policy *m_policy;
 };
 
 /* Global singleton.  */
@@ -159,7 +224,7 @@ extern rtx_reader *rtx_reader_ptr;
 class noop_reader : public rtx_reader
 {
  public:
-  noop_reader () : rtx_reader () {}
+  noop_reader () : rtx_reader (NULL) {}
 
   /* A dummy implementation which skips unknown directives.  */
   void handle_unknown_directive (file_location, const char *);
@@ -184,6 +249,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 *);
@@ -199,8 +266,11 @@ 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 read_name (struct md_name *);
+extern void require_word_ws (const char *expected);
+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..a108d5e
--- /dev/null
+++ b/gcc/read-rtl-function.c
@@ -0,0 +1,1197 @@
+/* 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"
+
+class function_reader;
+
+/* 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;
+};
+
+/* Subclass of rtx_reader for reading function dumps.  */
+
+class function_reader : public rtx_reader
+{
+ public:
+  function_reader (rtl_reader_policy *policy);
+  ~function_reader ();
+
+  void handle_unknown_directive (file_location, const char *);
+
+  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 create_function ();
+  void apply_fixups ();
+  void create_cfg_edges ();
+
+  rtx_insn **get_insn_by_uid (int uid);
+
+  rtx_insn *get_first_insn () const { return m_first_insn; }
+
+  tree parse_mem_expr (const char *desc);
+
+ private:
+  void create_cfg_and_basic_blocks ();
+
+ private:
+  struct uid_hash : int_hash <int, -1, -2> {};
+  hash_map<uid_hash, rtx_insn *> m_insns_by_uid;
+  auto_vec<fixup *> m_fixups;
+  bitmap_head m_bb_indices;
+  rtx_insn *m_first_insn;
+  auto_vec<tree> m_fake_scope;
+};
+
+/* 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));
+    }
+}
+
+/* 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)
+{
+  if (0 == strcmp (desc, "<retval>"))
+    {
+      tree fndecl = cfun->decl;
+      return DECL_RESULT (fndecl);
+    }
+
+  /* FIXME: use a hash rather than linear search.  */
+  int i;
+  tree t;
+  FOR_EACH_VEC_ELT (m_fake_scope, i, t)
+    if (0 == strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (t))))
+      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;
+}
+
+/* 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 ();
+    }
+}
+
+/* class function_reader : public rtx_reader */
+
+/* function_reader's constructor.  */
+
+function_reader::function_reader (rtl_reader_policy *policy)
+: rtx_reader (policy),
+  m_first_insn (NULL)
+{
+  bitmap_initialize (&m_bb_indices, NULL);
+  bitmap_set_bit (&m_bb_indices, ENTRY_BLOCK);
+  bitmap_set_bit (&m_bb_indices, EXIT_BLOCK);
+}
+
+/* function_reader's destructor.  */
+
+function_reader::~function_reader ()
+{
+  int i;
+  fixup *f;
+  FOR_EACH_VEC_ELT (m_fixups, i, f)
+    delete f;
+}
+
+/* Implementation of rtx_reader::handle_unknown_directive.
+   Parse rtx instructions by calling read_rtx_code, calling
+   set_first_insn and set_last_insn as appropriate.  */
+
+void
+function_reader::handle_unknown_directive (file_location /*start_loc*/,
+					   const char *name)
+{
+  rtx x = read_rtx_code (name);
+  if (!x)
+    return;
+  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);
+}
+
+/* Implementation of rtx_reader::add_fixup_insn_uid.
+   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));
+}
+
+/* Implementation of rtx_reader::add_fixup_bb.
+   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, bb_idx);
+  m_fixups.safe_push (new fixup_bb (loc, insn, operand_idx, bb_idx));
+}
+
+/* Implementation of rtx_reader::add_fixup_note_insn_basic_block.
+   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));
+}
+
+/* Implementation of rtx_reader::add_fixup_source_location.
+   Record the information for later post-processing.  */
+void
+function_reader::add_fixup_source_location (file_location, rtx,
+					    int, const char *, int)
+{
+  /* Empty for now.  */
+}
+
+/* Implementation of rtx_reader::add_fixup_jump_label.
+   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));
+}
+
+/* Implementation of rtx_reader::add_fixup_expr.
+   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));
+}
+
+/* Set up state for the function *before* fixups are applied.
+
+   Create "cfun" and a decl for the function.
+   For the moment, every function decl is hardcoded as
+      int test_1 (int i, int j, int k);
+   Set up various other state:
+   - state set up by expand_function_start (e.g. crtl->return_rtx).
+   - 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 ("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.  */
+
+  /* Normally, various state gets set up by expand_function_start, e.g.
+     crtl->return_rtx, based on DECL_RESULT (fndecl).
+     We call it here to ensure the state is set up, with emit_insns as
+     false, so no new instructions are emitted.  */
+  current_function_decl = fndecl;
+  expand_function_start (fndecl, false);
+
+  create_cfg_and_basic_blocks ();
+  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;
+  }
+}
+
+/* Apply all of the recorded fixups.  */
+
+void
+function_reader::apply_fixups ()
+{
+  /* line_table should now be populated; every deferred_location should
+     now have an m_srcloc.  */
+
+  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);
+}
+
+/* Create cfun's CFG and populate with blocks, a helper
+   function for function_reader::create_function ().
+
+   The edges are created later on, 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);
+  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, 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;
+}
+
+/* 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::create_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);
+	    }
+	}
+    }
+}
+
+static void
+postprocess (function_reader *reader)
+{
+  reader->create_function ();
+  reader->apply_fixups ();
+  reader->create_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 ();
+}
+
+bool
+read_rtl_function_body (int argc, const char **argv,
+			bool (*parse_opt) (const char *),
+			rtl_reader_policy *policy)
+{
+  initialize_rtl ();
+  init_emit ();
+  init_varasm_status ();
+
+  function_reader reader (policy);
+  if (!reader.read_md_files (argc, argv, parse_opt))
+    return false;
+
+  postprocess (&reader);
+
+  return true;
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that we can load RTL dumps.  */
+
+static void
+test_loading_dump_fragment_1 ()
+{
+  /* 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.  */
+  // TODO: filter on target?
+  const char *input_dump
+    = ("(insn 8 0 9 2 (set (reg:DI 78)\n"
+       "        (lshiftrt:DI (reg:DI 76)\n"
+       "            (const_int 32 [0x20])))\n"
+       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
+       "        641 {*aarch64_lshr_sisd_or_int_di3}\n"
+       "     (expr_list:REG_DEAD (reg:DI 76)\n"
+       "        (nil)))\n"
+       "(insn 9 8 0 2 (set (reg:SI 79)\n"
+       "        (ashiftrt:SI (subreg:SI (reg:DI 78) 0)\n"
+       "            (const_int 3 [0x3])))\n"
+       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
+       "        642 {*aarch64_ashr_sisd_or_int_si3}\n"
+       "     (expr_list:REG_DEAD (reg:DI 78)\n"
+       "        (nil)))\n");
+  const int dumped_first_pseudo_regno = 76;
+  rtl_dump_test t (input_dump, dumped_first_pseudo_regno);
+
+  /* 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.  */
+  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 ()
+{
+  const char *input_dump
+    =  ("(insn 2 0 0 2\n"
+	"  (set (mem/c:SI\n"
+	"          (plus:DI\n"
+	"            (reg/f:DI 20 frame)\n"
+	"            (const_int -4 [0xfffffffffffffffc]))\n"
+	"          [1 i+0 S4 A32])\n"
+	"       (reg:SI 5 di [ i ])) test.c:2 -1\n"
+	"     (nil))\n");
+  rtl_dump_test t (input_dump);
+
+  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 ()
+{
+  const char *input_dump
+    = ("(code_label 1 0 2 6 3 (nil) [0 uses])\n"
+       "(code_label 2 1 0 6 3 (\"some_label_name\") [57 uses])\n");
+  rtl_dump_test t (input_dump);
+
+  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 ()
+{
+  const char *input_dump
+    = "(insn:TI 31 0 0 2 (set (reg:SI 100) (reg:SI 101)) -1 (nil))";
+  const int dumped_first_pseudo_regno = 100;
+  rtl_dump_test t (input_dump, dumped_first_pseudo_regno);
+  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 ()
+{
+  const char *input_dump
+    = ("(jump_insn 1 0 2 4 (set (pc)\n"
+       "        (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1\n"
+       "     (nil)\n"
+       " -> 3)\n"
+       "(barrier 2 1 3)\n"
+       "(code_label 3 2 0 5 2 (nil) [1 uses])\n");
+  rtl_dump_test t (input_dump);
+
+  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));
+
+  // TODO: verify the generated CFG
+}
+
+/* Verify that the loader copes with a jump_insn to a label_ref
+   marked "return".  */
+
+static void
+test_loading_jump_to_return ()
+{
+  const char *input_dump
+    = ("(jump_insn 1 0 2 4 (set (pc)\n"
+       "        (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1\n"
+       "     (nil)\n"
+       " -> return)\n"
+       "(barrier 2 1 3)\n"
+       "(code_label 3 2 0 5 2 (nil) [1 uses])\n");
+  rtl_dump_test t (input_dump);
+
+  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 ()
+{
+  const char *input_dump
+    = ("(jump_insn 1 0 2 4 (set (pc)\n"
+       "        (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1\n"
+       "     (nil)\n"
+       " -> simple_return)\n"
+       "(barrier 2 1 3)\n"
+       "(code_label 3 2 0 5 2 (nil) [1 uses])\n");
+  rtl_dump_test t (input_dump);
+
+  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 ()
+{
+  const char *input_dump
+    = "(note 1 0 0 2 [bb 2] NOTE_INSN_BASIC_BLOCK)\n";
+  rtl_dump_test t (input_dump);
+
+  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 ()
+{
+  const char *input_dump
+    = "(note 1 0 0 (nil) NOTE_INSN_DELETED)\n";
+  rtl_dump_test t (input_dump);
+
+  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 ()
+{
+  const char *input_dump
+    =  ("(insn 100 0 101 2\n"
+	"  (set (reg:SI 100) (const_int 0 [0x0]))\n"
+	"  test.c:2 -1 (nil))\n"
+	"(insn 101 100 102 2\n"
+	"  (set (reg:SI 101) (const_int 1 [0x1]))\n"
+	"  test.c:2 -1 (nil))\n"
+	"(insn 102 101 103 2\n"
+	"  (set (reg:SI 102) (const_int -1 [0xffffffff]))\n"
+	"  test.c:2 -1 (nil))\n"
+	"(insn 103 102 0 2\n"
+	"  (set (reg:SI 103) (const_int 256 [0x100]))\n"
+	"  test.c:2 -1 (nil))\n");
+  rtl_dump_test t (input_dump);
+
+  /* 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 ()
+{
+  const char *input_dump
+    = ("(insn 1045 0 0 2 (set (reg:SI 480)\n"
+       "        (high:SI (symbol_ref:SI (\"isl_obj_map_vtable\") [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>))) y.c:12702 -1\n"
+       "     (nil))\n");
+  rtl_dump_test t (input_dump);
+  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.  */
+}
+
+/* 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 ();
+}
+
+} // 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..5cc0233
--- /dev/null
+++ b/gcc/read-rtl-function.h
@@ -0,0 +1,29 @@
+/* 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
+
+struct rtl_reader_policy;
+
+extern bool read_rtl_function_body (int argc, const char **argv,
+				    bool (*parse_opt) (const char *),
+				    rtl_reader_policy *policy);
+
+#endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index eda9382..ce5dbdb 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,10 +117,14 @@ 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 one_time_initialization (void);
 static rtx read_nested_rtx (void);
 static rtx read_rtx_variadic (rtx);
 
+#ifndef GENERATOR_FILE
+static rtx consolidate_singletons (rtx);
+#endif
+
 /* The mode and code iterator structures.  */
 static struct iterator_group modes, codes, ints, substs;
 
@@ -181,6 +196,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 +269,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 +437,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 +602,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 +677,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 +748,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 +791,7 @@ read_conditions (void)
       add_c_test (expr, value);
     }
 }
+#endif /* #ifdef GENERATOR_FILE */
 
 static void
 validate_const_int (const char *string)
@@ -861,6 +888,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 +1049,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,16 +1104,220 @@ 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;
+    }
+}
+
+#ifndef GENERATOR_FILE
+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);
+}
+
+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);
+}
+
+/* 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 maybe_read_location (int operand_idx, rtx insn)
+{
+  file_location loc = rtx_reader_ptr->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);
+
+  rtx_reader_ptr->add_fixup_source_location (loc, insn, operand_idx,
+					     filename, atoi(name.string));
+}
+
+/* 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.  */
+
+static char *
+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 ());
+}
+
+static void strip_trailing_whitespace (char *desc)
+{
+  char *terminator = desc + strlen (desc);
+  while (desc < terminator)
+    {
+      terminator--;
+      if (ISSPACE (*terminator))
+	*terminator = '\0';
+      else
+	break;
+    }
+}
+
+#endif /* #ifndef GENERATOR_FILE */
+
+/* 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);
+	}
+    }
+}
+
+/* Remap a register number in a dump to an equivalent register number
+   for the current target.  */
+
+unsigned int
+regno_remapper::get_effective_regno (int dumped_regno) const
+{
+  /* 0 means "do nothing".  */
+  if (m_dumped_first_pseudo_regno == 0)
+    return dumped_regno;
+
+  if (dumped_regno < m_dumped_first_pseudo_regno)
+    /* Assume we have a reference to a physical or virtual regno.
+       Do not remap.  */
+    return dumped_regno;
+
+  /* Otherwise, assume that DUMPED_REGNO was a pseudo reg.
+     Offset it to the correct range for pseudo regs for this target.  */
+  return (LAST_VIRTUAL_REGISTER + 1
+	  + (dumped_regno - m_dumped_first_pseudo_regno));
+}
+
+int
+rtx_reader::remap_regno (int dumped_regno) const
+{
+  if (!m_policy)
+    return dumped_regno;
+
+  if (!m_policy->m_regno_remapper)
+    return dumped_regno;
+
+  return m_policy->m_regno_remapper->get_effective_regno (dumped_regno);
+}
+
 /* 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.  */
 
-static rtx
+rtx
 read_rtx_code (const char *code_name)
 {
   int i;
   RTX_CODE code;
-  struct mapping *iterator, *m;
+  struct mapping *iterator = NULL, *m;
   const char *format_ptr;
   struct md_name name;
   rtx return_rtx;
@@ -1108,13 +1334,19 @@ 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);
@@ -1125,6 +1357,27 @@ 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.  */
+#ifndef GENERATOR_FILE
+  if (GET_CODE (return_rtx) == EXPR_LIST
+      || GET_CODE (return_rtx) == INSN_LIST
+      || GET_CODE (return_rtx) == INT_LIST)
+    {
+      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);
+    }
+#endif
+
   /* If what follows is `: mode ', read it and
      store the mode in the rtx.  */
 
@@ -1137,6 +1390,12 @@ read_rtx_code (const char *code_name)
   else
     unread_char (i);
 
+  if (INSN_CHAIN_CODE_P (code))
+    {
+      read_name (&name);
+      INSN_UID (return_rtx) = atoi (name.string);
+    }
+
   for (i = 0; format_ptr[i] != 0; i++)
     switch (format_ptr[i])
       {
@@ -1145,11 +1404,103 @@ read_rtx_code (const char *code_name)
       case '0':
 	if (code == REG)
 	  ORIGINAL_REGNO (return_rtx) = REGNO (return_rtx);
+	else if (i == 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 (i == 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).  */
+#ifndef GENERATOR_FILE
+	    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);
+		rtx_reader_ptr->add_fixup_note_insn_basic_block (bb_loc,
+								 return_rtx, i,
+								 bb_idx);
+		require_char_ws (']');
+	      }
+	    else
+	      unread_char (c);
+#endif /* #ifndef GENERATOR_FILE */
+	  }
+	else if (i == 7 && JUMP_P (return_rtx))
+	  {
+#ifndef GENERATOR_FILE
+	    c = read_skip_spaces ();
+	    if (c != '-')
+	      {
+		unread_char (c);
+		break;
+	      }
+	    require_char ('>');
+	    file_location loc = read_name (&name);
+	    rtx_reader_ptr->add_fixup_jump_label (loc, return_rtx, i, name.string);
+#endif /* #ifndef GENERATOR_FILE */
+	  }
 	break;
 
       case 'e':
+	XEXP (return_rtx, i) = read_nested_rtx ();
+	break;
+
       case 'u':
+#ifdef GENERATOR_FILE
 	XEXP (return_rtx, i) = read_nested_rtx ();
+#else
+	{
+	  /* 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.  */
+	  file_location loc = read_name (&name);
+	  int insn_id = atoi (name.string);
+	  if (insn_id)
+	    rtx_reader_ptr->add_fixup_insn_uid (loc, return_rtx, i, insn_id);
+	}
+#endif
 	break;
 
       case 'V':
@@ -1223,7 +1574,10 @@ read_rtx_code (const char *code_name)
 	  star_if_braced = (format_ptr[i] == '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
@@ -1246,6 +1600,7 @@ read_rtx_code (const char *code_name)
 	      obstack_grow (&string_obstack, line_name, strlen (line_name)+1);
 	      stringbuf = XOBFINISH (&string_obstack, char *);
 	    }
+#endif /* #ifdef GENERATOR_FILE */
 
 	  /* Find attr-names in the string.  */
 	  ptr = &tmpstr[0];
@@ -1275,10 +1630,21 @@ read_rtx_code (const char *code_name)
 		record_iterator_use (m, return_rtx);
 	    }
 
+	  /* "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 *ptr = stringbuf;
+#ifndef GENERATOR_FILE
+	  ptr = ggc_strdup (stringbuf);
+#endif /* #ifndef GENERATOR_FILE */
+
 	  if (star_if_braced)
-	    XTMPL (return_rtx, i) = stringbuf;
+	    XTMPL (return_rtx, i) = ptr;
 	  else
-	    XSTR (return_rtx, i) = stringbuf;
+	    XSTR (return_rtx, i) = ptr;
 	}
 	break;
 
@@ -1301,27 +1667,251 @@ read_rtx_code (const char *code_name)
 #endif
 #endif
 	XWINT (return_rtx, i) = tmp_wide;
+#ifndef GENERATOR_FILE
+	/* Strip away the redundant hex dump of the value.  */
+	{
+	  require_char_ws ('[');
+	  read_name (&name);
+	  require_char_ws (']');
+	}
+#endif
 	break;
 
       case 'i':
       case 'n':
+#ifdef GENERATOR_FILE
 	/* Can be an iterator or an integer constant.  */
 	read_name (&name);
 	record_potential_iterator_use (&ints, &XINT (return_rtx, i),
 				       name.string);
+#else
+	/* 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 (i == 5 && NOTE_P (return_rtx))
+	    break;
+
+	  if (i == 4 && INSN_P (return_rtx))
+	    {
+	      maybe_read_location (i, return_rtx);
+	      break;
+	    }
+
+	  read_name (&name);
+	  int value;
+	  if (format_ptr[i] == 'n')
+	    value = parse_note_insn_name (name.string);
+	  else
+	    value = atoi (name.string);
+	  XINT (return_rtx, i) = 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 (i == 5 && INSN_P (return_rtx) && format_ptr[i] == 'i')
+	    if (value >= 0)
+	      {
+		/* Reset the insn to be unrecognized.  */
+		INSN_CODE (return_rtx) = -1;
+
+		/* Skip the braces and their content.  */
+		require_char_ws ('{');
+		while (1)
+		  {
+		    char ch = read_char ();
+		    if (ch == '}')
+		      break;
+		  }
+	      }
+	}
+#endif
+	break;
+
+      case 'B':
+	{
+	  file_location loc = read_name_or_nil (&name);
+	  int bb_idx = atoi (name.string);
+	  if (bb_idx)
+	    rtx_reader_ptr->add_fixup_bb (loc, return_rtx, i, bb_idx);
+	}
 	break;
 
       case 'r':
-	read_name (&name);
-	validate_const_int (name.string);
-	set_regno_raw (return_rtx, atoi (name.string), 1);
-	REG_ATTRS (return_rtx) = NULL;
+	{
+	  read_name (&name);
+	  validate_const_int (name.string);
+
+	  int dumped_regno = atoi (name.string);
+	  int effective_regno = rtx_reader_ptr->remap_regno (dumped_regno);
+	  set_regno_raw (return_rtx, effective_regno, 1);
+
+	  REG_ATTRS (return_rtx) = NULL;
+#ifndef GENERATOR_FILE
+	  unsigned int regno = REGNO (return_rtx);
+	  ORIGINAL_REGNO (return_rtx) = regno;
+
+	  /* print_rtx can print a name for various registers
+	     after the register number.  Skip and discard it.  */
+	  if (effective_regno < FIRST_PSEUDO_REGISTER
+	      || effective_regno <= LAST_VIRTUAL_REGISTER)
+	    read_name (&name);
+
+	  /* Parse extra stuff at end of 'r'.
+	     We may have zero, one, or two sections marked by square
+	     brackets.  */
+	  int ch = read_skip_spaces ();
+	  bool expect_original_regno = false;
+	  if (ch == '[')
+	    {
+	      file_location loc = rtx_reader_ptr->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.  */
+		  rtx_reader_ptr->add_fixup_expr
+		    (loc, consolidate_singletons (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);
+	    }
+#endif
+	}
 	break;
 
       default:
 	gcc_unreachable ();
       }
 
+#ifndef GENERATOR_FILE
+  /* Handle the various additional information that print-rtl.c can
+     write after the regular fields.  */
+  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 = rtx_reader_ptr->get_current_location ();
+	      char *desc = read_until (" +", false);
+	      rtx_reader_ptr->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;
+    }
+#endif
+
   if (CONST_WIDE_INT_P (return_rtx))
     {
       read_name (&name);
@@ -1382,6 +1972,135 @@ read_rtx_code (const char *code_name)
   return return_rtx;
 }
 
+#ifndef GENERATOR_FILE
+
+/* Helper function for consolidate_reg.  */
+
+static rtx
+lookup_global_register (int regno)
+{
+  /* FIXME: do we need to check for Pmode? */
+  /* FIXME: should we instead look for the reg name, and
+     remap the number accordingly?  */
+  /* 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;
+}
+
+/* Helper function for consolidate_singletons, for handling REG instances.  */
+
+static rtx
+consolidate_reg (rtx x)
+{
+  gcc_assert (GET_CODE (x) == REG);
+
+  int regno = REGNO (x);
+
+  /* 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.  */
+  if (regno >= crtl->emit.regno_pointer_align_length)
+    {
+      int old_size = crtl->emit.regno_pointer_align_length;
+      int new_size = MAX (regno + 1, old_size * 2);
+      char *tmp;
+      rtx *new1;
+
+      tmp = XRESIZEVEC (char, crtl->emit.regno_pointer_align, new_size);
+      memset (tmp + old_size, 0, old_size);
+      crtl->emit.regno_pointer_align = (unsigned char *) tmp;
+
+      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;
+    }
+  gcc_assert (regno < crtl->emit.regno_pointer_align_length);
+
+  if (reg_rtx_no < regno + 1)
+    reg_rtx_no = regno + 1;
+
+  /* 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.  */
+
+static rtx
+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;
+}
+
+#endif /* #ifndef GENERATOR_FILE */
+
+
 /* Read a nested rtx construct from the MD file and return it.  */
 
 static rtx
@@ -1400,6 +2119,10 @@ read_nested_rtx (void)
 
   require_char_ws (')');
 
+#ifndef GENERATOR_FILE
+  return_rtx = consolidate_singletons (return_rtx);
+#endif /* #ifndef GENERATOR_FILE */
+
   return return_rtx;
 }
 
diff --git a/gcc/rtl.h b/gcc/rtl.h
index b531ab7..04f3e14 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3641,7 +3641,10 @@ 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
+extern rtx read_rtx_code (const char *code_name);
 
 /* In alias.c */
 extern rtx canon_rtx (rtx);
@@ -3746,5 +3749,6 @@ struct GTY(()) cgraph_rtl_info {
   unsigned function_used_regs_valid: 1;
 };
 
+extern rtx_insn *get_insn_by_uid (int uid);
 
 #endif /* ! GCC_RTL_H */
diff --git a/gcc/selftest-rtl.c b/gcc/selftest-rtl.c
new file mode 100644
index 0000000..9c67b1a
--- /dev/null
+++ b/gcc/selftest-rtl.c
@@ -0,0 +1,81 @@
+/* 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 "selftest-rtl.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Constructor for selftest::rtl_dump_test.
+   Create tempfile containing DUMP_CONTENT, and read it.  */
+
+rtl_dump_test::rtl_dump_test (const char *dump_content,
+			      int dumped_first_pseudo_regno)
+: /* Write out DUMP_CONTENT to a tempfile.  */
+  m_tempfile (SELFTEST_LOCATION, ".rtl", dump_content),
+
+  /* Remap registers >= dumped_first_pseudo_regno to be target-appropriate
+     pseudos, for the target's current value of LAST_VIRTUAL_REGISTER.  */
+  m_regno_remapper (dumped_first_pseudo_regno)
+{
+  rtl_reader_policy policy (&m_regno_remapper);
+
+  /* Parse the tempfile.  */
+  auto_vec<const char *> argv (2);
+  argv.safe_push (progname);
+  argv.safe_push (m_tempfile.get_filename ());
+  bool read_ok
+    = read_rtl_function_body (argv.length (), argv.address (), NULL, &policy);
+  ASSERT_TRUE (read_ok);
+}
+
+/* Destructor for selftest::rtl_dump_test.
+   Cleanup global state relating to the function.
+   Also, implicitly unlink the tempfile (via its dtor).  */
+
+selftest::rtl_dump_test::~rtl_dump_test ()
+{
+  /* Cleanups.  */
+  current_function_decl = NULL;
+  free_after_compilation (cfun);
+  set_cfun (NULL);
+}
+
+/* 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 m_regno_remapper.get_effective_regno (input_regno);
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-rtl.h b/gcc/selftest-rtl.h
new file mode 100644
index 0000000..a466925
--- /dev/null
+++ b/gcc/selftest-rtl.h
@@ -0,0 +1,66 @@
+/* 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-md.h"
+
+namespace selftest {
+
+/* A class for testing RTL function dumps.
+   Write DUMP_CONTENT to a tempfile and parse it as a function.
+   If non-zero, treat DUMPED_FIRST_PSEUDO_REGNO as the lowest-numbered
+   pseduoreg in the dump, remapping register numbers accordingly as
+   they are loaded.  */
+
+class rtl_dump_test
+{
+ public:
+  rtl_dump_test (const char *dump_content, int dumped_first_pseudo_regno = 0);
+  ~rtl_dump_test ();
+
+  unsigned int effective_regno (int input_regno) const;
+
+ private:
+  temp_source_file m_tempfile;
+  regno_remapper m_regno_remapper;
+};
+
+/* Wrapper class for initializing/cleaning up df.  */
+
+class dataflow_test
+{
+ public:
+  dataflow_test ();
+  ~dataflow_test ();
+};
+
+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 54a9b0f..c90037c 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -63,6 +63,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 86ad14c..75fea6f 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -203,6 +203,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/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] 56+ messages in thread

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-09  0:01 [PATCH 0/9] RFC: selftests based on RTL dumps David Malcolm
                   ` (8 preceding siblings ...)
  2016-09-09  0:13 ` [PATCH 5/9] Introduce class function_reader David Malcolm
@ 2016-09-12 14:14 ` Bernd Schmidt
  2016-09-12 18:59   ` David Malcolm
  9 siblings, 1 reply; 56+ messages in thread
From: Bernd Schmidt @ 2016-09-12 14:14 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

In general, it's functionality that I would very much like to have 
(although maybe it's less useful these days now that the rtl side is 
fairly static). I think there's not much sense looking too deeply at the 
individual patches yet; we need to first figure out what we would really 
like this to look like in the end.

> These tests are very target-specific and were developed mostly for
> target==x86_64, and a little for target==aarch64.
> I put clauses like this in the various test functions, which is a kludge:
>
>     /* Only run these tests for i386.  */
>  #ifndef I386_OPTS_H
>     return;
>  #endif
>
> Is there a better way to express this condition?  (I guess I could
> add a selftest::target_is_x86_p () predicate).

My preferred solution would still be a separate selftest backend, which 
could be built as a cross-compiler once in a separate top-level 
directory. That way we have control over it, and maintainers of actual 
targets don't need to fear breaking selftests when they make changes to 
their ports. The downside would primarily be the time to build it.

> +  const char *input_dump
> +    = ("(insn 8 0 9 2 (set (reg:DI 78)\n"
> +       "        (lshiftrt:DI (reg:DI 76)\n"
> +       "            (const_int 32 [0x20])))\n"
> +       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
> +       "        641 {*aarch64_lshr_sisd_or_int_di3}\n"
> +       "     (expr_list:REG_DEAD (reg:DI 76)\n"
> +       "        (nil)))\n"
> +       "(insn 9 8 0 2 (set (reg:SI 79)\n"
> +       "        (ashiftrt:SI (subreg:SI (reg:DI 78) 0)\n"
> +       "            (const_int 3 [0x3])))\n"
> +       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
> +       "        642 {*aarch64_ashr_sisd_or_int_si3}\n"
> +       "     (expr_list:REG_DEAD (reg:DI 78)\n"
> +       "        (nil)))\n");

I can sort of see the desire to just copy&paste dumps into this, but 
this strikes me as really ugly. Especially if we end up using real 
targets this hard-codes not just pattern structure but also pattern 
names, which I think is too great a burden on target maintainers.

It's also not unheard of for the insn structure to change a bit; I 
remember a change which swapped location and pattern (I think).

There's also a fairly large amount of visual clutter here, such as the 
input filenames.

Maybe there's room for a tool to take input dumps and convert them to 
something more readable, or maybe to a sequence of gen_/emit_ function 
calls?


Bernd

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

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-12 14:14 ` [PATCH 0/9] RFC: selftests based on RTL dumps Bernd Schmidt
@ 2016-09-12 18:59   ` David Malcolm
  2016-09-13 11:35     ` Bernd Schmidt
  2016-09-13 20:39     ` [PATCH 0/9] RFC: selftests based on RTL dumps Jeff Law
  0 siblings, 2 replies; 56+ messages in thread
From: David Malcolm @ 2016-09-12 18:59 UTC (permalink / raw)
  To: Bernd Schmidt, gcc-patches

On Mon, 2016-09-12 at 16:10 +0200, Bernd Schmidt wrote:
> In general, it's functionality that I would very much like to have 
> (although maybe it's less useful these days now that the rtl side is 
> fairly static). I think there's not much sense looking too deeply at
> the 
> individual patches yet; we need to first figure out what we would
> really 
> like this to look like in the end.
> 
> > These tests are very target-specific and were developed mostly for
> > target==x86_64, and a little for target==aarch64.
> > I put clauses like this in the various test functions, which is a
> > kludge:
> > 
> >     /* Only run these tests for i386.  */
> >  #ifndef I386_OPTS_H
> >     return;
> >  #endif
> > 
> > Is there a better way to express this condition?  (I guess I could
> > add a selftest::target_is_x86_p () predicate).
> 
> My preferred solution would still be a separate selftest backend,
> which 
> could be built as a cross-compiler once in a separate top-level 
> directory. That way we have control over it, and maintainers of
> actual 
> targets don't need to fear breaking selftests when they make changes
> to 
> their ports. The downside would primarily be the time to build it.

I'm not sure I follow - this sounds like a dedicated target for
selftesting.

Would it be a separate configuration i.e. something like:
   ../src/configure --target=rtl-selftest
or somesuch?

> > +  const char *input_dump
> > +    = ("(insn 8 0 9 2 (set (reg:DI 78)\n"
> > +       "        (lshiftrt:DI (reg:DI 76)\n"
> > +       "            (const_int 32 [0x20])))\n"
> > +       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
> > +       "        641 {*aarch64_lshr_sisd_or_int_di3}\n"
> > +       "     (expr_list:REG_DEAD (reg:DI 76)\n"
> > +       "        (nil)))\n"
> > +       "(insn 9 8 0 2 (set (reg:SI 79)\n"
> > +       "        (ashiftrt:SI (subreg:SI (reg:DI 78) 0)\n"
> > +       "            (const_int 3 [0x3])))\n"
> > +       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
> > +       "        642 {*aarch64_ashr_sisd_or_int_si3}\n"
> > +       "     (expr_list:REG_DEAD (reg:DI 78)\n"
> > +       "        (nil)))\n");
> 
> I can sort of see the desire to just copy&paste dumps into this, but 
> this strikes me as really ugly. Especially if we end up using real 
> targets this hard-codes not just pattern structure but also pattern 
> names, which I think is too great a burden on target maintainers.

Note that the loader now resets INSN_CODE to -1, regardless of the
actual code passed in, to force re-recognition, and to isolate the
dumps somewhat from changes to the .md files.  So although the above
says insn 641 and 642 (for some snapshot of the aarch64 md file), it
gets reset to -1.


> It's also not unheard of for the insn structure to change a bit; I 
> remember a change which swapped location and pattern (I think).
> 
> There's also a fairly large amount of visual clutter here, such as
> the 
> input filenames.
> 
> Maybe there's room for a tool to take input dumps and convert them to
> something more readable, or maybe to a sequence of gen_/emit_
> function 
> calls?

(such a tool could use the loader class, and e.g. strip out the
location information).

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

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-12 18:59   ` David Malcolm
@ 2016-09-13 11:35     ` Bernd Schmidt
  2016-09-14 10:33       ` Bernd Schmidt
  2016-09-16 20:26       ` Jeff Law
  2016-09-13 20:39     ` [PATCH 0/9] RFC: selftests based on RTL dumps Jeff Law
  1 sibling, 2 replies; 56+ messages in thread
From: Bernd Schmidt @ 2016-09-13 11:35 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/12/2016 08:57 PM, David Malcolm wrote:

> I'm not sure I follow - this sounds like a dedicated target for
> selftesting.
>
> Would it be a separate configuration i.e. something like:
>    ../src/configure --target=rtl-selftest
> or somesuch?

The way I imagine it working, the top-level Makefile would create a 
selftest-gcc/ subdirectory, and run a configure line much like the above 
inside it. It would live independently of the real compiler we're 
building in gcc/.

That's not something I'm deciding, it needs a broader consensus. But I 
feel pretty strongly that this is how things should be organized.

>>> +  const char *input_dump
>>> +    = ("(insn 8 0 9 2 (set (reg:DI 78)\n"
>>> +       "        (lshiftrt:DI (reg:DI 76)\n"
>>> +       "            (const_int 32 [0x20])))\n"
>>> +       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
>>> +       "        641 {*aarch64_lshr_sisd_or_int_di3}\n"
>>> +       "     (expr_list:REG_DEAD (reg:DI 76)\n"
>>> +       "        (nil)))\n"
>>> +       "(insn 9 8 0 2 (set (reg:SI 79)\n"
>>> +       "        (ashiftrt:SI (subreg:SI (reg:DI 78) 0)\n"
>>> +       "            (const_int 3 [0x3])))\n"
>>> +       "        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14\n"
>>> +       "        642 {*aarch64_ashr_sisd_or_int_si3}\n"
>>> +       "     (expr_list:REG_DEAD (reg:DI 78)\n"
>>> +       "        (nil)))\n");
>>
>> I can sort of see the desire to just copy&paste dumps into this, but
>> this strikes me as really ugly. Especially if we end up using real
>> targets this hard-codes not just pattern structure but also pattern
>> names, which I think is too great a burden on target maintainers.
>
> Note that the loader now resets INSN_CODE to -1, regardless of the
> actual code passed in, to force re-recognition, and to isolate the
> dumps somewhat from changes to the .md files.  So although the above
> says insn 641 and 642 (for some snapshot of the aarch64 md file), it
> gets reset to -1.

Best to find out a way to avoid including it in the strings then, to 
avoid confusion.


Bernd

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

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-12 18:59   ` David Malcolm
  2016-09-13 11:35     ` Bernd Schmidt
@ 2016-09-13 20:39     ` Jeff Law
  2016-09-14  8:44       ` Richard Biener
  1 sibling, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-13 20:39 UTC (permalink / raw)
  To: David Malcolm, Bernd Schmidt, gcc-patches

On 09/12/2016 12:57 PM, David Malcolm wrote:
>
> I'm not sure I follow - this sounds like a dedicated target for
> selftesting.
That's exactly what it is.  We'd essentially put in knobs so that we 
could control the different things we need to.   For example, if we 
wanted to test a particular problem with promotions of arguments, we can 
do that.  If we wanted to test how we handled a secondary address reload 
to implemenet a GP<->FP register copy through memory, we can control all 
the parameters for that too.  And so on.

It's Bernd's idea and I think it has a lot of merit and I think it's 
largely complementary to what you're doing.

jeff

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

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-13 20:39     ` [PATCH 0/9] RFC: selftests based on RTL dumps Jeff Law
@ 2016-09-14  8:44       ` Richard Biener
  2016-09-16 20:16         ` Jeff Law
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2016-09-14  8:44 UTC (permalink / raw)
  To: Jeff Law; +Cc: David Malcolm, Bernd Schmidt, GCC Patches

On Tue, Sep 13, 2016 at 10:37 PM, Jeff Law <law@redhat.com> wrote:
> On 09/12/2016 12:57 PM, David Malcolm wrote:
>>
>>
>> I'm not sure I follow - this sounds like a dedicated target for
>> selftesting.
>
> That's exactly what it is.  We'd essentially put in knobs so that we could
> control the different things we need to.   For example, if we wanted to test
> a particular problem with promotions of arguments, we can do that.  If we
> wanted to test how we handled a secondary address reload to implemenet a
> GP<->FP register copy through memory, we can control all the parameters for
> that too.  And so on.
>
> It's Bernd's idea and I think it has a lot of merit and I think it's largely
> complementary to what you're doing.

Note that while the "snippets" may largely work (not sure how many you
tried to come up with)
I see the issue that a lot of RTL "unit tests" would need some trees
set up, like to properly
form MEM_EXPRs or REG_DECL or even SYMBOL_REFs.  So I fear that the scope of
unit-tests we can implement with the proposed scheme is very limited
(you may also need
other stuff setup, like alias analysis or parts of IRA or cost
analysis parts).  So I agree a
separate testing backend is a good way to make unit-testing more
stable on the target side
we also need a way to provide input on some of the global state that
is currently set up
by frontends.

But my biggest worry is with putting unit-tests into cc1 itself --
even more so with RTL
unit tests of this kind than with all the other ones we have.  We'll
quickly have 99% of a
source file comprised of RTL unit tests rather than source (and cc1
object size as well).
Hardly something we want to have (not even mentioning bootstrap time issues).

Yes, putting the unit-tests in source files makes us not require
exporting an interface
to the parts we are testing.  But that's about the only advantage I
can see.  You didn't
show that it isn't possible to put the small test you were writing
into a RTL-frontendish
test which starts compiling the function with the test with the pass
you are about
to unit-test.

Richard.

> jeff
>

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

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-13 11:35     ` Bernd Schmidt
@ 2016-09-14 10:33       ` Bernd Schmidt
  2016-09-16 20:26       ` Jeff Law
  1 sibling, 0 replies; 56+ messages in thread
From: Bernd Schmidt @ 2016-09-14 10:33 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

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

On 09/13/2016 01:15 PM, Bernd Schmidt wrote:
> On 09/12/2016 08:57 PM, David Malcolm wrote:
>
>> I'm not sure I follow - this sounds like a dedicated target for
>> selftesting.
>>
>> Would it be a separate configuration i.e. something like:
>>    ../src/configure --target=rtl-selftest
>> or somesuch?
>
> The way I imagine it working, the top-level Makefile would create a
> selftest-gcc/ subdirectory, and run a configure line much like the above
> inside it. It would live independently of the real compiler we're
> building in gcc/.

The Makefile goop would look something like this, adapted from the old 
accel-gcc stuff we had on gomp-4_0-branch. Autogenerated files are 
omitted, run autogen/autoconf.
It's gated on an --enable switch. While it would be nice to include it 
in every build, it would probably not be worth the extra build time 
until such a time when we've built up a fairly large library of tests.

I picked ia64-elf as a stand-in for now. I guess if we decide to go down 
this path we can start trying to decide what we want the actual backend 
to look like.


Bernd

[-- Attachment #2: testgcc.diff --]
[-- Type: text/x-patch, Size: 3218 bytes --]

Index: Makefile.def
===================================================================
--- Makefile.def	(revision 240029)
+++ Makefile.def	(working copy)
@@ -47,6 +47,9 @@ host_modules= { module= flex; no_check_c
 host_modules= { module= gas; bootstrap=true; };
 host_modules= { module= gcc; bootstrap=true; 
 		extra_make_flags="$(EXTRA_GCC_FLAGS)"; };
+host_modules= { module= test-gcc;
+	        module_srcdir=gcc;
+		no_install= true; };
 host_modules= { module= gmp; lib_path=.libs; bootstrap=true;
 		// Work around in-tree gmp configure bug with missing flex.
 		extra_configure_flags='--disable-shared LEX="touch lex.yy.c"';
Index: Makefile.tpl
===================================================================
--- Makefile.tpl	(revision 240029)
+++ Makefile.tpl	(working copy)
@@ -1047,6 +1047,11 @@ configure-[+prefix+][+module+]: [+ IF bo
 	$(SHELL) $(srcdir)/mkinstalldirs [+subdir+]/[+module+]; \
 	[+exports+] [+extra_exports+] \
 	echo Configuring in [+subdir+]/[+module+]; \
+	[+ IF (= (get "module") "test-gcc") +] \
+	this_target="ia64-elf"; \
+	[+ ELSE +] \
+	this_target="[+target_alias+]"; \
+	[+ ENDIF +] \
 	cd "[+subdir+]/[+module+]" || exit 1; \
 	case $(srcdir) in \
 	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
@@ -1059,7 +1064,7 @@ configure-[+prefix+][+module+]: [+ IF bo
 	  $$s/$$module_srcdir/configure \
 	  --srcdir=$${topdir}/$$module_srcdir \
 	  [+args+] --build=${build_alias} --host=[+host_alias+] \
-	  --target=[+target_alias+] [+extra_configure_flags+] \
+	  --target=$${this_target} [+extra_configure_flags+] \
 	  || exit 1
 @endif [+prefix+][+module+]
 
Index: configure.ac
===================================================================
--- configure.ac	(revision 240029)
+++ configure.ac	(working copy)
@@ -140,7 +140,7 @@ host_libs="intl libiberty opcodes bfd re
 # binutils, gas and ld appear in that order because it makes sense to run
 # "make check" in that particular order.
 # If --enable-gold is used, "gold" may replace "ld".
-host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen sid sim gdb gprof etc expect dejagnu m4 utils guile fastjar gnattools libcc1 gotools"
+host_tools="texinfo flex bison binutils gas ld fixincludes test-gcc gcc cgen sid sim gdb gprof etc expect dejagnu m4 utils guile fastjar gnattools libcc1 gotools"
 
 # libgcj represents the runtime libraries only used by gcj.
 libgcj="target-libffi \
@@ -305,6 +305,15 @@ AC_ARG_ENABLE(offload-targets,
   fi
 ], [enable_offload_targets=])
 
+AC_ARG_ENABLE(gcc-rtl-test,
+[AS_HELP_STRING([[--enable-gcc-rtl-test[=ARG]]],
+		[build the rtl selftest compiler])],
+ENABLE_RTL_SELFTEST=$enableval,
+ENABLE_RTL_SELFTEST=no)
+case "${ENABLE_RTL_SELFTEST}" in
+  no) skipdirs="${skipdirs} test-gcc" ;;
+esac
+
 # Handle --enable-gold, --enable-ld.
 # --disable-gold [--enable-ld]
 #     Build only ld.  Default option.
@@ -2246,7 +2255,15 @@ done
 configdirs_all="$configdirs"
 configdirs=
 for i in ${configdirs_all} ; do
-  if test -f ${srcdir}/$i/configure ; then
+  case $i in
+    test-gcc)
+      confsrcdir=gcc
+      ;;
+    *)
+      confsrcdir=$i
+      ;;
+  esac
+  if test -f ${srcdir}/${confsrcdir}/configure ; then
     configdirs="${configdirs} $i"
   fi
 done

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

* Re: [PATCH 3/9] selftest.h: add temp_override fixture
  2016-09-09  0:01 ` [PATCH 3/9] selftest.h: add temp_override fixture David Malcolm
@ 2016-09-14 22:24   ` Trevor Saunders
  2016-09-16 20:37   ` Jeff Law
  1 sibling, 0 replies; 56+ messages in thread
From: Trevor Saunders @ 2016-09-14 22:24 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches

On Thu, Sep 08, 2016 at 08:30:47PM -0400, David Malcolm wrote:
> 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.

I expect there are uses for this outside of selftests, so I'd suggest
making it more general.  I guess the name is good enough, I would have
done auto_restore, but this is fine.  You just need to put it somewhere
generally accessible though I'm not sure what that would be.

Trev

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

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-14  8:44       ` Richard Biener
@ 2016-09-16 20:16         ` Jeff Law
  2016-09-16 21:27           ` David Malcolm
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-16 20:16 UTC (permalink / raw)
  To: Richard Biener; +Cc: David Malcolm, Bernd Schmidt, GCC Patches

On 09/14/2016 02:37 AM, Richard Biener wrote:
>
> Note that while the "snippets" may largely work (not sure how many
> you tried to come up with) I see the issue that a lot of RTL "unit
> tests" would need some trees set up, like to properly form MEM_EXPRs
> or REG_DECL or even SYMBOL_REFs.  So I fear that the scope of
> unit-tests we can implement with the proposed scheme is very limited
> (you may also need other stuff setup, like alias analysis or parts of
> IRA or cost analysis parts).  So I agree a separate testing backend
> is a good way to make unit-testing more stable on the target side we
> also need a way to provide input on some of the global state that is
> currently set up by frontends.
Agreed across the board.  I think we're still early in the learning 
phase on this stuff.   I shudder when I think about the amount of state 
that we depend on, but which is not represented in the RTL dumps.

But I do think there are some things we can test for in an RTL self 
testing framework and that having one would be a significant step forward.

So I think we have two big questions.

First, does David's work have value as a way to directly test pieces of 
the RTL pipeline without having to generate all the RTL bits by hand.  I 
think the answer is yes.

Second, will David's work help identify internal state that is not 
expressed in the RTL dumps or poor modularity (ie, cases like trees 
embedded within the RTL structures).  I think the answer to this is yes 
as well.

Third, is a framework like Bernd's useful as well and can it be mated 
with David's work.  And I think the answer is yes & yes as well with the 
result being more useful than either Bernd or David's work in isolation.

>
> But my biggest worry is with putting unit-tests into cc1 itself --
> even more so with RTL unit tests of this kind than with all the other
> ones we have.  We'll quickly have 99% of a source file comprised of
> RTL unit tests rather than source (and cc1 object size as well).
> Hardly something we want to have (not even mentioning bootstrap time
> issues).
I can live revisiting this -- I always expected we would after we 
started building out the framework.

>
> Yes, putting the unit-tests in source files makes us not require
> exporting an interface to the parts we are testing.  But that's about
> the only advantage I can see.  You didn't show that it isn't possible
> to put the small test you were writing into a RTL-frontendish test
> which starts compiling the function with the test with the pass you
> are about to unit-test.
The other advantage is tests which use the internal APIs are easy to 
identify/fix when an internal API is changed.

Jeff

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

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-13 11:35     ` Bernd Schmidt
  2016-09-14 10:33       ` Bernd Schmidt
@ 2016-09-16 20:26       ` Jeff Law
  2016-09-16 21:28         ` David Malcolm
  1 sibling, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-16 20:26 UTC (permalink / raw)
  To: Bernd Schmidt, David Malcolm, gcc-patches

On 09/13/2016 05:15 AM, Bernd Schmidt wrote:
>>
>> Note that the loader now resets INSN_CODE to -1, regardless of the
>> actual code passed in, to force re-recognition, and to isolate the
>> dumps somewhat from changes to the .md files.  So although the above
>> says insn 641 and 642 (for some snapshot of the aarch64 md file), it
>> gets reset to -1.
>
> Best to find out a way to avoid including it in the strings then, to
> avoid confusion.
We should also twiddle how we represent registers in the dumps. 
Identifying hard regs by name (so we can map back to a hard reg if the 
hard regs change), identifying pseudos by number that isn't affected if 
the hard register set changes ie, p0, p1, p2, p3 where the number is 
REGNO (x) - FIRST_PSEUDO_REGISTER. identifying the virtual registers, etc.

The key being rather than put a ton of smarts/hacks in a reader, we 
should work to have the RTL writer give us something more useful.  That 
may mean simple changes to the output, or some conditional changes (like 
not emitting the INSN_CODE or its name).

jeff

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

* Re: [PATCH 4/9] Expose forcibly_ggc_collect and run it after all selftests
  2016-09-09  0:01 ` [PATCH 4/9] Expose forcibly_ggc_collect and run it after all selftests David Malcolm
@ 2016-09-16 20:30   ` Jeff Law
  0 siblings, 0 replies; 56+ messages in thread
From: Jeff Law @ 2016-09-16 20:30 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/08/2016 06:30 PM, David Malcolm wrote:
> 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.
>
> 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.
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.

jeff

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

* Re: [PATCH 9/9] cse.c selftests
  2016-09-09  0:01 ` [PATCH 9/9] cse.c selftests David Malcolm
@ 2016-09-16 20:34   ` Jeff Law
  2016-09-16 21:28     ` David Malcolm
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-16 20:34 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/08/2016 06:30 PM, David Malcolm wrote:
> 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.
So as I look at this, the first thing that comes to mind is whether or 
not to refine the dump output.

There's a lot of useless crap in there that really only helps folks that 
sitting inside a debugger dumping hunks of RTL (I'm thinking 
specifically about the pointers back to tree nodes for DECLs).  Those 
addresses are useless in other contexts.

When possible I don't think we want the tests to be target specific. 
Hmm, I'm probably about to argue for Bernd's work...  The 71779 testcase 
is a great example -- it uses high/lo_sum.  Not all targets support that 
-- as long as we don't try to recognize those insns we're likely OK, but 
that seems fragile long term.  Having an idealized target means we can 
ignore much of these issues.



> ---
>  gcc/cse.c                | 109 +++++++++++++++++++++++++++++++++++++++++++++++
>  gcc/selftest-run-tests.c |   1 +
>  gcc/selftest.h           |   1 +
>  3 files changed, 111 insertions(+)
>
> diff --git a/gcc/cse.c b/gcc/cse.c
> index 0bfd7ff..f4f06fe 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,110 @@ 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.  */
So I'm real curious, what happens if you run this RTL selftest under 
valgrind?  I have the sneaking suspicion that we'll start doing some 
uninitialized memory reads.


> +
> +static void
> +test_simple_cse ()
> +{
> +  /* Only run this tests for i386.  */
> +#ifndef I386_OPTS_H
> +  return;
> +#endif
> +
> +  const char *input_dump
> +    = (/* "r101 = r100 + 1;" */
> +       "(insn 1 0 2 2 (set (reg:SI 101)\n"
> +       "                   (plus:SI (reg:SI 100)\n"
> +       "                            (const_int 1 [0x1]))) -1 (nil))\n"
> +       /* "r102 = r100 + 1;" */
> +       "(insn 2 1 3 2 (set (reg:SI 102)\n"
> +       "                   (plus:SI (reg:SI 100)\n"
> +       "                            (const_int 1 [0x1]))) -1 (nil))\n"
> +       /* "*r103 = r101 * r102;" */
> +       "(insn 3 2 0 2 (set (mem:SI (reg:SI 103) [1 i+0 S4 A32])\n"
> +       "                   (mult:SI (reg:SI 101) (reg:SI 102))) -1 (nil))\n"
> +       );
I don't think we need to comment each RTL insn for those which are so 
obvious.  It just adds to the visual clutter.


  +
> +  /* 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.  */
> +  const char *input_dump
> +    = (";; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;\n"
> +       "(insn 1045 0 1046 2 (set (reg:SI 480)\n"
> +       "        (high:SI (symbol_ref:SI (\"isl_obj_map_vtable\") [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>))) y.c:12702 -1\n"
> +       "     (nil))\n"
> +       "(insn 1046 1045 1047 2 (set (reg/f:SI 479)\n"
> +       "        (lo_sum:SI (reg:SI 480)\n"
> +       "            (symbol_ref:SI (\"isl_obj_map_vtable\") [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>))) y.c:12702 -1\n"
> +       "     (expr_list:REG_EQUAL (symbol_ref:SI (\"isl_obj_map_vtable\") [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)\n"
> +       "        (nil)))\n"
> +       "(insn 1047 1046 1048 2 (set (reg:DI 481)\n"
> +       "        (subreg:DI (reg/f:SI 479) 0)) y.c:12702 -1\n"
> +       "     (nil))\n"
> +       "(insn 1048 1047 1049 2 (set (zero_extract:DI (reg/v:DI 191 [ obj1D.17368 ])\n"
> +       "            (const_int 32 [0x20])\n"
> +       "            (const_int 0 [0]))\n"
> +       "        (reg:DI 481)) y.c:12702 -1\n"
> +       "     (nil))\n"
So looking at this just makes my head hurt.  Escaping, lots of quotes, 
unnecessary things in the dump, etc.  The question I would have is why 
not have a file with the dump and read the file?


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

* Re: [PATCH 3/9] selftest.h: add temp_override fixture
  2016-09-09  0:01 ` [PATCH 3/9] selftest.h: add temp_override fixture David Malcolm
  2016-09-14 22:24   ` Trevor Saunders
@ 2016-09-16 20:37   ` Jeff Law
  1 sibling, 0 replies; 56+ messages in thread
From: Jeff Law @ 2016-09-16 20:37 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/08/2016 06:30 PM, David Malcolm wrote:
> 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.
When you need it, this is fine.

jeff

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

* Re: [PATCH 6/9] df selftests
  2016-09-09  0:01 ` [PATCH 6/9] df selftests David Malcolm
@ 2016-09-16 20:40   ` Jeff Law
  2016-09-16 21:34     ` David Malcolm
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-16 20:40 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/08/2016 06:30 PM, David Malcolm wrote:
> 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/df-core.c            | 77 ++++++++++++++++++++++++++++++++++++++++++++++++
>  gcc/selftest-run-tests.c |  1 +
>  gcc/selftest.h           |  1 +
>  3 files changed, 79 insertions(+)
>
> diff --git a/gcc/df-core.c b/gcc/df-core.c
> index e531d58..cb8e2f9 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,78 @@ 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 ()
> +{
> +  const char *input_dump
> +    = "(insn 1 0 0 2 (set (reg:SI 100) (reg:SI 101)) -1 (nil))\n";
> +  rtl_dump_test t (input_dump, 100);
> +  //print_rtl_with_bb (stdout, get_insns (), 1024);
Obviously this call to pritn_rtl_with_bb should disappear...


> +
> +  dataflow_test dftest;
> +
> +  df_note_add_problem ();
> +  df_analyze ();
> +  //df_dump (stderr);
ANd this call to df_dump.

> +
> +  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));
I don't think the ordering of the notes is guaranteed.

Like the other RTL test I've looked at, I'd be real curious to know if 
you get any uninitialized memory reads if you run this test under valgrind.

jeff

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

* Re: [PATCH 7/9] combine.c selftests
  2016-09-09  0:01 ` [PATCH 7/9] combine.c selftests David Malcolm
@ 2016-09-16 20:45   ` Jeff Law
  2016-09-16 21:39     ` David Malcolm
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-16 20:45 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/08/2016 06:30 PM, David Malcolm wrote:
> 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.
> diff --git a/gcc/combine.c b/gcc/combine.c
> index 1b262f9..9c148bb 100644
> --- a/gcc/combine.c
> +++ b/gcc/combine.c
> @@ -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);
Presumably when you set up the self test the first time this was NULL :-)

> +
> +/* combine_test's constructor.  Write DUMP_CONTENT to a tempfile and load
> +   it.  Initialize df and perform dataflow analysis.  */
> +
> +combine_test::combine_test (const char *dump_content,
> +			    int dumped_first_pseudo_regno)
> +: rtl_dump_test (dump_content, dumped_first_pseudo_regno),
> +  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 ();
> +}
So rather than taking a string (which is a pain to construct), then 
writing it out to a file, then reading it in, what's wrong with having 
RTL fragments in a file?


Jeff

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

* Re: [PATCH 8/9] final.c selftests
  2016-09-09  0:01 ` [PATCH 8/9] final.c selftests David Malcolm
@ 2016-09-16 21:12   ` Jeff Law
  2016-09-16 21:41     ` David Malcolm
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-16 21:12 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/08/2016 06:30 PM, David Malcolm wrote:
> gcc/ChangeLog:
> 	* final.c: Include selftest.h and selftest-rtl.h.
> 	(class selftest::temp_asm_out): New subclass of
> 	selftest::named_temp_file.
> 	(selftest::temp_asm_out::temp_asm_out): New ctor.
> 	(selftest::temp_asm_out::~temp_asm_out): New dtor.
> 	(class selftest::asm_out_test): New subclass of
> 	selftest::rtl_dump_test.
> 	(selftest::asm_out_test::asm_out_test): New ctor.
> 	(selftest::test_jump_insn): New function.
> 	(selftest::test_empty_function): New function.
> 	(selftest::test_asm_for_insn): New function.
> 	(TEST_ASM_FOR_INSN): New macro.
> 	(selftest::test_x86_64_leal): New function.
> 	(selftest::test_x86_64_negl): New function.
> 	(selftest::test_x86_64_cmpl): New function.
> 	(selftest::test_x86_64_cmovge): New function.
> 	(selftest::test_x86_64_ret): New function.
> 	(selftest::final_c_tests): New function.
> 	* selftest-run-tests.c (selftest::run_tests): Call
> 	selftest::final_c_tests.
> 	* selftest.h (selftest::final_c_tests): New decl.
I'm really not sure how useful these tests are going to be and would 
question the long term maintenance costs of keeping them up-to-date.

I could see perhaps verifying that when there are multiple alternatives 
that the correct one is selected or somesuch, but these tests really 
don't seem to be covering anything particularly useful.

Jeff

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

* Re: [PATCH 2/9] Add selftest::read_file
  2016-09-09  0:01 ` [PATCH 2/9] Add selftest::read_file David Malcolm
@ 2016-09-16 21:19   ` Jeff Law
  0 siblings, 0 replies; 56+ messages in thread
From: Jeff Law @ 2016-09-16 21:19 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/08/2016 06:30 PM, David Malcolm wrote:
> 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.
Seems reasonable.  Install when you have a need.

jeff

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

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-16 20:16         ` Jeff Law
@ 2016-09-16 21:27           ` David Malcolm
  2016-09-19 12:21             ` Bernd Schmidt
  0 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-16 21:27 UTC (permalink / raw)
  To: Jeff Law, Richard Biener; +Cc: Bernd Schmidt, GCC Patches

On Fri, 2016-09-16 at 14:00 -0600, Jeff Law wrote:
> On 09/14/2016 02:37 AM, Richard Biener wrote:
> > 
> > Note that while the "snippets" may largely work (not sure how many
> > you tried to come up with) I see the issue that a lot of RTL "unit
> > tests" would need some trees set up, like to properly form
> > MEM_EXPRs
> > or REG_DECL or even SYMBOL_REFs.  So I fear that the scope of
> > unit-tests we can implement with the proposed scheme is very
> > limited
> > (you may also need other stuff setup, like alias analysis or parts
> > of
> > IRA or cost analysis parts).  So I agree a separate testing backend
> > is a good way to make unit-testing more stable on the target side
> > we
> > also need a way to provide input on some of the global state that
> > is
> > currently set up by frontends.
> Agreed across the board.  I think we're still early in the learning 
> phase on this stuff.   I shudder when I think about the amount of
> state 
> that we depend on, but which is not represented in the RTL dumps.
> 
> But I do think there are some things we can test for in an RTL self 
> testing framework and that having one would be a significant step
> forward.
> 
> So I think we have two big questions.
> 
> First, does David's work have value as a way to directly test pieces
> of 
> the RTL pipeline without having to generate all the RTL bits by hand.
>   I 
> think the answer is yes.
> 
> Second, will David's work help identify internal state that is not 
> expressed in the RTL dumps or poor modularity (ie, cases like trees 
> embedded within the RTL structures).  I think the answer to this is
> yes 
> as well.
> 
> Third, is a framework like Bernd's useful as well and can it be mated
> with David's work.  And I think the answer is yes & yes as well with
> the 
> result being more useful than either Bernd or David's work in
> isolation.

As far as I understand Bernd's suggestion there seem to be two parts to
it:
(a) a kind of virtual target, which can act in different ways depending
on the needs of a test case.  e.g. dynamically  select 32 bit vs 64
bit, does it have a CCmode, how many stages is the pipeline etc etc.
(b) a separate build of the "gcc" subdir, configured to use (a).

These seem like laudable goal, but I see it as orthogonal to my patch
kit.  It'd also be a massive expansion of scope.

Also, re (a) any given test is likely to be tested against a specific
target. That could be a real target, or a particular setting of a
virtual target.  The tests in my patch kit have largely gated on the
specific targets I was testing with.

So is Bernd's suggestion a prerequisite for my work, or can my work
stand alone from it?

> > 
> > But my biggest worry is with putting unit-tests into cc1 itself --
> > even more so with RTL unit tests of this kind than with all the
> > other
> > ones we have.  We'll quickly have 99% of a source file comprised of
> > RTL unit tests rather than source (and cc1 object size as well).
> > Hardly something we want to have (not even mentioning bootstrap
> > time
> > issues).
> I can live revisiting this -- I always expected we would after we 
> started building out the framework.

There are some interrelated questions here:
(a) where do the dumps live? (string fragments embedded in the source
file vs external files)
(b) -fself-test vs DejaGnu tests that use a real frontend.  In the
latter case, is the frontend "rtl1", or an extension of "cc1" with an
"__RTL" marker?

For (a), I'd like to do support both (in that it's clear we need
support for external files, but it seems trivial to support embedding).
 I've worked with both approaches in the past, and both are useful (a
two-liner may make sense to live "inline", as they get larger you'd
want them in a separate file).

For (b), I'd like to do both: if nothing else, the loader itself needs
selftests.  Plus selftests allow for tests that are more fine-grained
than just the level of one optimization pass.  But I'd anticipate most
of them being external.

For selftests that load external files, there's a slight wart - how are
they accessed?  There needs to be some way to tell it which directory
to look in.  Also, what happens when build != host?

I have some followup patches that both build out an actual frontend on
top of the loader, and extend cc1, but there's some ugly diagnostic and
linemap issues to resolve.


> > 
> > Yes, putting the unit-tests in source files makes us not require
> > exporting an interface to the parts we are testing.  But that's
> > about
> > the only advantage I can see.  You didn't show that it isn't
> > possible
> > to put the small test you were writing into a RTL-frontendish test
> > which starts compiling the function with the test with the pass you
> > are about to unit-test.
> The other advantage is tests which use the internal APIs are easy to 
> identify/fix when an internal API is changed.
> 
> Jeff
> 

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

* Re: [PATCH 9/9] cse.c selftests
  2016-09-16 20:34   ` Jeff Law
@ 2016-09-16 21:28     ` David Malcolm
  2016-09-19 17:37       ` Jeff Law
  0 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-16 21:28 UTC (permalink / raw)
  To: Jeff Law, gcc-patches

On Fri, 2016-09-16 at 14:26 -0600, Jeff Law wrote:
> On 09/08/2016 06:30 PM, David Malcolm wrote:
> > 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.
> So as I look at this, the first thing that comes to mind is whether
> or 
> not to refine the dump output.
> 
> There's a lot of useless crap in there that really only helps folks
> that 
> sitting inside a debugger dumping hunks of RTL (I'm thinking 
> specifically about the pointers back to tree nodes for DECLs).  Those
> addresses are useless in other contexts.
> 
> When possible I don't think we want the tests to be target specific. 
> Hmm, I'm probably about to argue for Bernd's work...  The 71779
> testcase 
> is a great example -- it uses high/lo_sum.  Not all targets support
> that 
> -- as long as we don't try to recognize those insns we're likely OK,
> but 
> that seems fragile long term.  Having an idealized target means we
> can 
> ignore much of these issues.

An alternative would be to pick a specific target for each test.


> > ---
> >  gcc/cse.c                | 109
> > +++++++++++++++++++++++++++++++++++++++++++++++
> >  gcc/selftest-run-tests.c |   1 +
> >  gcc/selftest.h           |   1 +
> >  3 files changed, 111 insertions(+)
> > 
> > diff --git a/gcc/cse.c b/gcc/cse.c
> > index 0bfd7ff..f4f06fe 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,110 @@ 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.  */
> So I'm real curious, what happens if you run this RTL selftest under 
> valgrind?  I have the sneaking suspicion that we'll start doing some 
> uninitialized memory reads.

I'm seeing various leaks (an htab within linemap_init for all of the
line_table fixtures), but no uninitialized reads.

> > +
> > +static void
> > +test_simple_cse ()
> > +{
> > +  /* Only run this tests for i386.  */
> > +#ifndef I386_OPTS_H
> > +  return;
> > +#endif
> > +
> > +  const char *input_dump
> > +    = (/* "r101 = r100 + 1;" */
> > +       "(insn 1 0 2 2 (set (reg:SI 101)\n"
> > +       "                   (plus:SI (reg:SI 100)\n"
> > +       "                            (const_int 1 [0x1]))) -1
> > (nil))\n"
> > +       /* "r102 = r100 + 1;" */
> > +       "(insn 2 1 3 2 (set (reg:SI 102)\n"
> > +       "                   (plus:SI (reg:SI 100)\n"
> > +       "                            (const_int 1 [0x1]))) -1
> > (nil))\n"
> > +       /* "*r103 = r101 * r102;" */
> > +       "(insn 3 2 0 2 (set (mem:SI (reg:SI 103) [1 i+0 S4 A32])\n"
> > +       "                   (mult:SI (reg:SI 101) (reg:SI 102))) -1
> > (nil))\n"
> > +       );
> I don't think we need to comment each RTL insn for those which are so
> obvious.  It just adds to the visual clutter.

This may have been more for my benefit; I'm still relatively new to RTL
:)

>   +
> > +  /* 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.  */
> > +  const char *input_dump
> > +    = (";; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;\n"
> > +       "(insn 1045 0 1046 2 (set (reg:SI 480)\n"
> > +       "        (high:SI (symbol_ref:SI (\"isl_obj_map_vtable\")
> > [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
> > y.c:12702 -1\n"
> > +       "     (nil))\n"
> > +       "(insn 1046 1045 1047 2 (set (reg/f:SI 479)\n"
> > +       "        (lo_sum:SI (reg:SI 480)\n"
> > +       "            (symbol_ref:SI (\"isl_obj_map_vtable\") [flags
> > 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>))) y.c:12702 
> > -1\n"
> > +       "     (expr_list:REG_EQUAL (symbol_ref:SI
> > (\"isl_obj_map_vtable\") [flags 0xc0] <var_decl 0x7fa0363ea240
> > isl_obj_map_vtable>)\n"
> > +       "        (nil)))\n"
> > +       "(insn 1047 1046 1048 2 (set (reg:DI 481)\n"
> > +       "        (subreg:DI (reg/f:SI 479) 0)) y.c:12702 -1\n"
> > +       "     (nil))\n"
> > +       "(insn 1048 1047 1049 2 (set (zero_extract:DI (reg/v:DI 191
> > [ obj1D.17368 ])\n"
> > +       "            (const_int 32 [0x20])\n"
> > +       "            (const_int 0 [0]))\n"
> > +       "        (reg:DI 481)) y.c:12702 -1\n"
> > +       "     (nil))\n"
> So looking at this just makes my head hurt.  Escaping, lots of
> quotes, 
> unnecessary things in the dump, etc.  The question I would have is
> why 
> not have a file with the dump and read the file?
 
(nods)

Seems like I need to add a mechanism for telling the selftests which
directory to load the tests relative to.

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

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-16 20:26       ` Jeff Law
@ 2016-09-16 21:28         ` David Malcolm
  2016-09-19 17:50           ` Jeff Law
  0 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-16 21:28 UTC (permalink / raw)
  To: Jeff Law, Bernd Schmidt, gcc-patches

On Fri, 2016-09-16 at 14:05 -0600, Jeff Law wrote:
> On 09/13/2016 05:15 AM, Bernd Schmidt wrote:
> > > 
> > > Note that the loader now resets INSN_CODE to -1, regardless of
> > > the
> > > actual code passed in, to force re-recognition, and to isolate
> > > the
> > > dumps somewhat from changes to the .md files.  So although the
> > > above
> > > says insn 641 and 642 (for some snapshot of the aarch64 md file),
> > > it
> > > gets reset to -1.
> > 
> > Best to find out a way to avoid including it in the strings then,
> > to
> > avoid confusion.
> We should also twiddle how we represent registers in the dumps. 
> Identifying hard regs by name (so we can map back to a hard reg if
> the 
> hard regs change), identifying pseudos by number that isn't affected
> if 
> the hard register set changes ie, p0, p1, p2, p3 where the number is 
> REGNO (x) - FIRST_PSEUDO_REGISTER. identifying the virtual registers, 
> etc.

Good idea.

I don't know if you saw this yet, but the patch has logic from
renumbering pseudos on load (see class regno_remapper), but dumping
them as p0, p1 etc and reloading them as such seems much easier for
everyone.

> The key being rather than put a ton of smarts/hacks in a reader, we 
> should work to have the RTL writer give us something more useful. 
>  That 
> may mean simple changes to the output, or some conditional changes
> (like 
> not emitting the INSN_CODE or its name).

That would make the reader a lot less grim; it has a lot of warts for
dealing with all the special cases in the current output format.

But maybe it is useful to be able to deal with the current output
format.  For example, I was able to look at PR 71779 and find some
fragmentary RTL dumps there (comment #2) and use them.  I *did* need to
edit them a little, so maybe it's OK to require a little editing
(especially with older dumps... to what extent has the format changed
over the years?)

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

* Re: [PATCH 5/9] Introduce class function_reader
  2016-09-09  0:13 ` [PATCH 5/9] Introduce class function_reader David Malcolm
@ 2016-09-16 21:31   ` Jeff Law
  2016-09-16 22:04     ` David Malcolm
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-16 21:31 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/08/2016 06:30 PM, David Malcolm wrote:
> 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.

> 	* cfgexpand.c (pass_expand::execute): Move stack initializations
> 	to rtl_data::init_stack_alignment and call it.  Pass "true"
> 	for new "emit_insns" param of expand_function_start.
> 	* 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.
> 	(rtl_data::init_stack_alignment): New method.
> 	(get_insn_by_uid): New function.
> 	* emit-rtl.h (rtl_data::init_stack_alignment): New method.
> 	* 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)).
> 	(expand_function_start): Add param "emit_insns", and use it to
> 	guard the various gen/emit calls.
> 	* function.h (emit_status::ensure_regno_capacity): New method.
> 	(expand_function_start): Add bool param to decl.
> 	* gensupport.c (gen_reader::gen_reader): Add NULL for new policy
> 	param of rtx_reader ctor.
> 	* 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 '/'.
> 	(require_char): New function.
> 	(require_word_ws): New function.
> 	(peek_char): New function.
> 	(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.  */
> 	(rtx_reader::rtx_reader): Add rtl_reader_policy * param, using
> 	it to initialize m_policy.
> 	(rtx_reader::~rtx_reader): Free m_base_dir.  Clean up global data.
> 	* read-md.h (struct file_location): Move to errors.h.
> 	(file_location::file_location): Likewise.
> 	Include errors.h.
> 	(class regno_remapper): New class.
> 	(struct rtl_reader_policy): New struct.
> 	(rtx_reader::rtx_reader): Add rtl_reader_policy * param.
> 	(rtx_reader::add_fixup_insn_uid): New vfunc.
> 	(rtx_reader::add_fixup_bb): New vfunc.
> 	(rtx_reader::add_fixup_note_insn_basic_block): New vfunc.
> 	(rtx_reader::add_fixup_source_location): New vfunc.
> 	(rtx_reader::add_fixup_jump_label): New vfunc.
> 	(rtx_reader::add_fixup_expr): New vfunc.
> 	(rtx_reader::remap_regno): New method.
> 	(rtx_reader::m_policy): New field.
> 	(noop_reader::noop_reader): Add NULL for new policy param of
> 	rtx_reader ctor.
> 	(peek_char): New decl.
> 	(require_char): New decl.
> 	(require_word_ws): New decl.
> 	(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.
> 	(read_rtx): Likewise.  Move one-time initialization logic to...
> 	(one_time_initialization): New function.
> 	(parse_reg_note_name): New function.
> 	(parse_note_insn_name): New function.
> 	(maybe_read_location): New function.
> 	(read_until): New function.
> 	(strip_trailing_whitespace): New function.
> 	(read_flags): New function.
> 	(regno_remapper::get_effective_regno): New method.
> 	(rtx_reader::remap_regno): New method.
> 	(read_rtx_code): Remove "static".  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 SYMBOL_REF data, REG_NOTE names,
> 	INSN_UID values, note-specific data, basic block IDs,
> 	jump labels, hexdump values of wide ints, REG_EXPR, MEM_EXPR,
> 	skipping recognized insn names, remapping register numbers.
> 	When on host, reallocate XSTR and XTMPL fields in the GC-managed
> 	heap.
> 	(lookup_global_register): New function.
> 	(consolidate_reg): New function.
> 	(consolidate_singletons): New function.
> 	(read_nested_rtx): Call consolidate_singletons.
> 	* rtl.h (read_rtx): Wrap decl with #ifdef GENERATOR_FILE.
> 	(read_rtx_code): New decl.
> 	* 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.
So I see a couple conceptual things going on here.

First is initialization/finalization/state handling and various fallout 
items.  Essentially it encompasses all changes that we can make a case 
are useful cleanups and should be handled independently.

Second is all the grunt work necessary to suck in a RTL reader into the 
target's cc1.  The Makefile.in changes, all the GENERATOR_FILE stuff, 
and of course the new rtx_reader class, regno_mapper and the like.

I think that'll allow us to spend more time looking at the raw mechanics 
of how to pull in an RTL reader into cc1.

Jeff

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

* Re: [PATCH 6/9] df selftests
  2016-09-16 20:40   ` Jeff Law
@ 2016-09-16 21:34     ` David Malcolm
  0 siblings, 0 replies; 56+ messages in thread
From: David Malcolm @ 2016-09-16 21:34 UTC (permalink / raw)
  To: Jeff Law, gcc-patches

On Fri, 2016-09-16 at 14:34 -0600, Jeff Law wrote:
> On 09/08/2016 06:30 PM, David Malcolm wrote:
> > 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/df-core.c            | 77
> > ++++++++++++++++++++++++++++++++++++++++++++++++
> >  gcc/selftest-run-tests.c |  1 +
> >  gcc/selftest.h           |  1 +
> >  3 files changed, 79 insertions(+)
> > 
> > diff --git a/gcc/df-core.c b/gcc/df-core.c
> > index e531d58..cb8e2f9 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,78 @@ 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 ()
> > +{
> > +  const char *input_dump
> > +    = "(insn 1 0 0 2 (set (reg:SI 100) (reg:SI 101)) -1 (nil))\n";
> > +  rtl_dump_test t (input_dump, 100);
> > +  //print_rtl_with_bb (stdout, get_insns (), 1024);
> Obviously this call to pritn_rtl_with_bb should disappear...
> 
> 
> > +
> > +  dataflow_test dftest;
> > +
> > +  df_note_add_problem ();
> > +  df_analyze ();
> > +  //df_dump (stderr);
> ANd this call to df_dump.
> 
> > +
> > +  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));
> I don't think the ordering of the notes is guaranteed.
> 
> Like the other RTL test I've looked at, I'd be real curious to know
> if 
> you get any uninitialized memory reads if you run this test under
> valgrind.

FWIW there don't seem to be any.

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

* Re: [PATCH 7/9] combine.c selftests
  2016-09-16 20:45   ` Jeff Law
@ 2016-09-16 21:39     ` David Malcolm
  0 siblings, 0 replies; 56+ messages in thread
From: David Malcolm @ 2016-09-16 21:39 UTC (permalink / raw)
  To: Jeff Law, gcc-patches

On Fri, 2016-09-16 at 14:40 -0600, Jeff Law wrote:
> On 09/08/2016 06:30 PM, David Malcolm wrote:
> > 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.
> > diff --git a/gcc/combine.c b/gcc/combine.c
> > index 1b262f9..9c148bb 100644
> > --- a/gcc/combine.c
> > +++ b/gcc/combine.c
> > @@ -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);
> Presumably when you set up the self test the first time this was NULL
> :-)

Indeed :)

> > +
> > +/* combine_test's constructor.  Write DUMP_CONTENT to a tempfile
> > and load
> > +   it.  Initialize df and perform dataflow analysis.  */
> > +
> > +combine_test::combine_test (const char *dump_content,
> > +			    int dumped_first_pseudo_regno)
> > +: rtl_dump_test (dump_content, dumped_first_pseudo_regno),
> > +  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 ();
> > +}
> So rather than taking a string (which is a pain to construct), then 
> writing it out to a file, then reading it in, what's wrong with
> having 
> RTL fragments in a file?
> 

I plan to rework these fixtures so that they can accept both string
fragments and filenames.

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

* Re: [PATCH 8/9] final.c selftests
  2016-09-16 21:12   ` Jeff Law
@ 2016-09-16 21:41     ` David Malcolm
  2016-09-19 21:38       ` Jeff Law
  0 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-16 21:41 UTC (permalink / raw)
  To: Jeff Law, gcc-patches

On Fri, 2016-09-16 at 14:45 -0600, Jeff Law wrote:
> On 09/08/2016 06:30 PM, David Malcolm wrote:
> > gcc/ChangeLog:
> > 	* final.c: Include selftest.h and selftest-rtl.h.
> > 	(class selftest::temp_asm_out): New subclass of
> > 	selftest::named_temp_file.
> > 	(selftest::temp_asm_out::temp_asm_out): New ctor.
> > 	(selftest::temp_asm_out::~temp_asm_out): New dtor.
> > 	(class selftest::asm_out_test): New subclass of
> > 	selftest::rtl_dump_test.
> > 	(selftest::asm_out_test::asm_out_test): New ctor.
> > 	(selftest::test_jump_insn): New function.
> > 	(selftest::test_empty_function): New function.
> > 	(selftest::test_asm_for_insn): New function.
> > 	(TEST_ASM_FOR_INSN): New macro.
> > 	(selftest::test_x86_64_leal): New function.
> > 	(selftest::test_x86_64_negl): New function.
> > 	(selftest::test_x86_64_cmpl): New function.
> > 	(selftest::test_x86_64_cmovge): New function.
> > 	(selftest::test_x86_64_ret): New function.
> > 	(selftest::final_c_tests): New function.
> > 	* selftest-run-tests.c (selftest::run_tests): Call
> > 	selftest::final_c_tests.
> > 	* selftest.h (selftest::final_c_tests): New decl.
> I'm really not sure how useful these tests are going to be and would 
> question the long term maintenance costs of keeping them up-to-date.
> 
> I could see perhaps verifying that when there are multiple
> alternatives 
> that the correct one is selected or somesuch, but these tests really 
> don't seem to be covering anything particularly useful.

My thinking here was that it might be useful to verify insn recognition
and output when someone is bringing up a new target, or adding new
insns to a .md file; the selftest::test_x86_64_cmpl show the beginnings
of how one might write that in selftest form.

But I'm happy to drop it.
Dave

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

* Re: [PATCH 5/9] Introduce class function_reader
  2016-09-16 21:31   ` Jeff Law
@ 2016-09-16 22:04     ` David Malcolm
  2016-09-19 21:39       ` Jeff Law
  0 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-16 22:04 UTC (permalink / raw)
  To: Jeff Law, gcc-patches

On Fri, 2016-09-16 at 15:28 -0600, Jeff Law wrote:
> On 09/08/2016 06:30 PM, David Malcolm wrote:
> > 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.
> 
> > 	* cfgexpand.c (pass_expand::execute): Move stack
> > initializations
> > 	to rtl_data::init_stack_alignment and call it.  Pass "true"
> > 	for new "emit_insns" param of expand_function_start.
> > 	* 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.
> > 	(rtl_data::init_stack_alignment): New method.
> > 	(get_insn_by_uid): New function.
> > 	* emit-rtl.h (rtl_data::init_stack_alignment): New method.
> > 	* 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)).
> > 	(expand_function_start): Add param "emit_insns", and use it to
> > 	guard the various gen/emit calls.
> > 	* function.h (emit_status::ensure_regno_capacity): New method.
> > 	(expand_function_start): Add bool param to decl.
> > 	* gensupport.c (gen_reader::gen_reader): Add NULL for new
> > policy
> > 	param of rtx_reader ctor.
> > 	* 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 '/'.
> > 	(require_char): New function.
> > 	(require_word_ws): New function.
> > 	(peek_char): New function.
> > 	(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.  */
> > 	(rtx_reader::rtx_reader): Add rtl_reader_policy * param, using
> > 	it to initialize m_policy.
> > 	(rtx_reader::~rtx_reader): Free m_base_dir.  Clean up global
> > data.
> > 	* read-md.h (struct file_location): Move to errors.h.
> > 	(file_location::file_location): Likewise.
> > 	Include errors.h.
> > 	(class regno_remapper): New class.
> > 	(struct rtl_reader_policy): New struct.
> > 	(rtx_reader::rtx_reader): Add rtl_reader_policy * param.
> > 	(rtx_reader::add_fixup_insn_uid): New vfunc.
> > 	(rtx_reader::add_fixup_bb): New vfunc.
> > 	(rtx_reader::add_fixup_note_insn_basic_block): New vfunc.
> > 	(rtx_reader::add_fixup_source_location): New vfunc.
> > 	(rtx_reader::add_fixup_jump_label): New vfunc.
> > 	(rtx_reader::add_fixup_expr): New vfunc.
> > 	(rtx_reader::remap_regno): New method.
> > 	(rtx_reader::m_policy): New field.
> > 	(noop_reader::noop_reader): Add NULL for new policy param of
> > 	rtx_reader ctor.
> > 	(peek_char): New decl.
> > 	(require_char): New decl.
> > 	(require_word_ws): New decl.
> > 	(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.
> > 	(read_rtx): Likewise.  Move one-time initialization logic to...
> > 	(one_time_initialization): New function.
> > 	(parse_reg_note_name): New function.
> > 	(parse_note_insn_name): New function.
> > 	(maybe_read_location): New function.
> > 	(read_until): New function.
> > 	(strip_trailing_whitespace): New function.
> > 	(read_flags): New function.
> > 	(regno_remapper::get_effective_regno): New method.
> > 	(rtx_reader::remap_regno): New method.
> > 	(read_rtx_code): Remove "static".  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 SYMBOL_REF data, REG_NOTE names,
> > 	INSN_UID values, note-specific data, basic block IDs,
> > 	jump labels, hexdump values of wide ints, REG_EXPR, MEM_EXPR,
> > 	skipping recognized insn names, remapping register numbers.
> > 	When on host, reallocate XSTR and XTMPL fields in the GC
> > -managed
> > 	heap.
> > 	(lookup_global_register): New function.
> > 	(consolidate_reg): New function.
> > 	(consolidate_singletons): New function.
> > 	(read_nested_rtx): Call consolidate_singletons.
> > 	* rtl.h (read_rtx): Wrap decl with #ifdef GENERATOR_FILE.
> > 	(read_rtx_code): New decl.
> > 	* 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.
> So I see a couple conceptual things going on here.
> 
> First is initialization/finalization/state handling and various
> fallout 
> items.  Essentially it encompasses all changes that we can make a
> case 
> are useful cleanups and should be handled independently.

I think you've described patch 1 of the kit :)

> Second is all the grunt work necessary to suck in a RTL reader into
> the 
> target's cc1.  The Makefile.in changes, all the GENERATOR_FILE stuff,
> and of course the new rtx_reader class, regno_mapper and the like.
> 
> I think that'll allow us to spend more time looking at the raw
> mechanics 
> of how to pull in an RTL reader into cc1.
> 
> Jeff

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

* Re: [PATCH 1/9] Introduce class rtx_reader
  2016-09-09  0:01 ` [PATCH 1/9] Introduce class rtx_reader David Malcolm
@ 2016-09-16 22:15   ` Jeff Law
  2016-09-21 17:22     ` [PATCH, v2] " David Malcolm
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-16 22:15 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/08/2016 06:30 PM, David Malcolm wrote:
> Bundle up various global variables within gensupport.c into a
> class rtx_reader, with a view towards making it easier to run the
> code more than once in-process.
>
> gcc/ChangeLog:
> 	* genconstants.c (main): Introduce noop_reader and convert call
> 	to read_md_files to a method call.
> 	* genenums.c (main): Likewise.
> 	* genmddeps.c (main): Likewise.
> 	* genpreds.c (write_tm_constrs_h): Replace use of "in_fname" with
> 	rtx_reader_ptr->get_top_level_filename ().
> 	(write_tm_preds_h): Likewise.
> 	(write_insn_preds_c): Likewise.
> 	* gensupport.c (class gen_reader): New subclass of rtx_reader.
> 	(rtx_handle_directive): Convert to...
> 	(gen_reader::handle_unknown_directive): ...this.
> 	(init_rtx_reader_args_cb): Convert return type from bool to
> 	rtx_reader *.  Create a gen_reader instance, using it for the
> 	call to read_md_files.  Return it if no errors occur.
> 	(init_rtx_reader_args): Convert return type from bool to
> 	rtx_reader *.
> 	* gensupport.h (init_rtx_reader_args_cb): Likewise.
> 	(init_rtx_reader_args_cb): Likewise.
> 	* read-md.c (struct file_name_list): Move to class rtx_reader.
> 	(read_md_file): Delete in favor of rtx_reader::m_read_md_file.
> 	(read_md_filename): Delete in favor of
> 	rtx_reader::m_read_md_filename.
> 	(read_md_lineno): Delete in favor of rtx_reader::m_read_md_lineno.
> 	(in_fname): Delete in favor of rtx_reader::m_toplevel_fname.
> 	(base_dir): Delete in favor of rtx_reader::m_base_dir.
> 	(first_dir_md_include): Delete in favor of
> 	rtx_reader::m_first_dir_md_include.
> 	(last_dir_md_include_ptr): Delete in favor of
> 	rtx_reader::m_last_dir_md_include_ptr.
> 	(max_include_len): Delete.
> 	(rtx_reader_ptr): New.
> 	(fatal_with_file_and_line): Use get_filename and get_lineno
> 	accessors of rtx_reader_ptr.
> 	(require_char_ws): Likewise.
> 	(rtx_reader::read_char): New method, based on ::read_char.
> 	(rtx_reader::unread_char): New method, based on ::unread_char.
> 	(read_escape): Use get_filename and get_lineno accessors of
> 	rtx_reader_ptr.
> 	(read_braced_string): Use get_lineno accessor of rtx_reader_ptr.
> 	(read_string): Use get_filename and get_lineno accessors of
> 	rtx_reader_ptr.
> 	(rtx_reader::rtx_reader): New ctor.
> 	(rtx_reader::~rtx_reader): New dtor.
> 	(handle_include): Convert from a function to...
> 	(rtx_reader::handle_include): ...this method, converting
> 	handle_directive from a callback to a virtual function.
> 	(handle_file): Likewise, converting to...
> 	(rtx_reader::handle_file): ...this method.
> 	(handle_toplevel_file): Likewise, converting to...
> 	(rtx_reader::handle_toplevel_file): ...this method.
> 	(rtx_reader::get_current_location): New method.
> 	(parse_include): Convert from a function to...
> 	(rtx_reader::add_include_path): ...this method, dropping redundant
> 	update to unused max_include_len.
> 	(read_md_files): Convert from a function to...
> 	(rtx_reader::read_md_files): ...this method, converting
> 	handle_directive from a callback to a virtual function.
> 	(noop_reader::handle_unknown_directive): New method.
> 	* read-md.h (directive_handler_t): Delete this typedef.
> 	(in_fname): Delete.
> 	(read_md_file): Delete.
> 	(read_md_lineno): Delete.
> 	(read_md_filename): Delete.
> 	(class rtx_reader): New class.
> 	(rtx_reader_ptr): New decl.
> 	(class noop_reader): New subclass of rtx_reader.
> 	(read_char): Reimplement in terms of rtx_reader::read_char.
> 	(unread_char): Reimplement in terms of rtx_reader::unread_char.
> 	(read_md_files): Delete.
> 	* read-rtl.c (read_rtx_code): Update for deletion of globals
> 	read_md_filename and read_md_lineno.
I don't see anything terribly objectionable here.

It looks like you use a singleton to avoid passing the object around 
everywhere, but given the state of all this prior to this patch, I can 
live with the cleanup as a whole.

I'll note Richard Sandiford. hasn't chimed in here.  You might ping him 
directly to see if he's got any feedback.  If he doesn't prior to say 
Wed, this is OK for the trunk.

jeff

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

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-16 21:27           ` David Malcolm
@ 2016-09-19 12:21             ` Bernd Schmidt
  0 siblings, 0 replies; 56+ messages in thread
From: Bernd Schmidt @ 2016-09-19 12:21 UTC (permalink / raw)
  To: David Malcolm, Jeff Law, Richard Biener; +Cc: GCC Patches

On 09/16/2016 11:12 PM, David Malcolm wrote:
> There are some interrelated questions here:
> (a) where do the dumps live? (string fragments embedded in the source
> file vs external files)
> (b) -fself-test vs DejaGnu tests that use a real frontend.  In the
> latter case, is the frontend "rtl1", or an extension of "cc1" with an
> "__RTL" marker?

I think a rtl1 frontend that gets run from a specific subdirectory in 
testsuite/ is probably the best option.

> For (a), I'd like to do support both (in that it's clear we need
> support for external files, but it seems trivial to support embedding).

If we're dealing with small snippets, I'm not sure embedding them as 
strings is really that much better than building them up with gen_ 
functions. I'm sure there's room for rtl selftests living inside the 
compiler like that, but anything larger probably ought to live outside.


Bernd

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

* Re: [PATCH 9/9] cse.c selftests
  2016-09-16 21:28     ` David Malcolm
@ 2016-09-19 17:37       ` Jeff Law
  2016-09-22  3:23         ` [PATCH] Introduce selftest::locate_file David Malcolm
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-19 17:37 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/16/2016 03:19 PM, David Malcolm wrote:
>
>> When possible I don't think we want the tests to be target specific.
>> Hmm, I'm probably about to argue for Bernd's work...  The 71779
>> testcase
>> is a great example -- it uses high/lo_sum.  Not all targets support
>> that
>> -- as long as we don't try to recognize those insns we're likely OK,
>> but
>> that seems fragile long term.  Having an idealized target means we
>> can
>> ignore much of these issues.
>
> An alternative would be to pick a specific target for each test.
It's an alternative, but not one I particularly like since those tests 
won't be consistently run.  With an abstracted target like Bernd 
suggests we ought to be able to make most tests work with the abstracted 
target and minimize the number of truely target specific tests.


>> So I'm real curious, what happens if you run this RTL selftest under
>> valgrind?  I have the sneaking suspicion that we'll start doing some
>> uninitialized memory reads.
>
> I'm seeing various leaks (an htab within linemap_init for all of the
> line_table fixtures), but no uninitialized reads.
Wow.  I must say I'm surprised.  Good news though.


>>   +
>>> +  /* 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.  */
>>> +  const char *input_dump
>>> +    = (";; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;\n"
>>> +       "(insn 1045 0 1046 2 (set (reg:SI 480)\n"
>>> +       "        (high:SI (symbol_ref:SI (\"isl_obj_map_vtable\")
>>> [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
>>> y.c:12702 -1\n"
>>> +       "     (nil))\n"
>>> +       "(insn 1046 1045 1047 2 (set (reg/f:SI 479)\n"
>>> +       "        (lo_sum:SI (reg:SI 480)\n"
>>> +       "            (symbol_ref:SI (\"isl_obj_map_vtable\") [flags
>>> 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>))) y.c:12702
>>> -1\n"
>>> +       "     (expr_list:REG_EQUAL (symbol_ref:SI
>>> (\"isl_obj_map_vtable\") [flags 0xc0] <var_decl 0x7fa0363ea240
>>> isl_obj_map_vtable>)\n"
>>> +       "        (nil)))\n"
>>> +       "(insn 1047 1046 1048 2 (set (reg:DI 481)\n"
>>> +       "        (subreg:DI (reg/f:SI 479) 0)) y.c:12702 -1\n"
>>> +       "     (nil))\n"
>>> +       "(insn 1048 1047 1049 2 (set (zero_extract:DI (reg/v:DI 191
>>> [ obj1D.17368 ])\n"
>>> +       "            (const_int 32 [0x20])\n"
>>> +       "            (const_int 0 [0]))\n"
>>> +       "        (reg:DI 481)) y.c:12702 -1\n"
>>> +       "     (nil))\n"
>> So looking at this just makes my head hurt.  Escaping, lots of
>> quotes,
>> unnecessary things in the dump, etc.  The question I would have is
>> why
>> not have a file with the dump and read the file?
>
> (nods)
>
> Seems like I need to add a mechanism for telling the selftests which
> directory to load the tests relative to.
What about putting them inside the appropriate gcc.target directories? 
We could have one for the "generic" target assuming we build something 
like that, the others could live in their target specific directory.


jeff

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

* Re: [PATCH 0/9] RFC: selftests based on RTL dumps
  2016-09-16 21:28         ` David Malcolm
@ 2016-09-19 17:50           ` Jeff Law
  2016-09-20 14:34             ` Register numbers in RTL dumps (was Re: [PATCH 0/9] RFC: selftests based on RTL dumps) David Malcolm
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-19 17:50 UTC (permalink / raw)
  To: David Malcolm, Bernd Schmidt, gcc-patches

On 09/16/2016 03:27 PM, David Malcolm wrote:
>> We should also twiddle how we represent registers in the dumps.
>> Identifying hard regs by name (so we can map back to a hard reg if
>> the
>> hard regs change), identifying pseudos by number that isn't affected
>> if
>> the hard register set changes ie, p0, p1, p2, p3 where the number is
>> REGNO (x) - FIRST_PSEUDO_REGISTER. identifying the virtual registers,
>> etc.
>
> Good idea.
>
> I don't know if you saw this yet, but the patch has logic from
> renumbering pseudos on load (see class regno_remapper), but dumping
> them as p0, p1 etc and reloading them as such seems much easier for
> everyone.
And just an FYI, I think we should do this unconditionally in our dumps.

>
>> The key being rather than put a ton of smarts/hacks in a reader, we
>> should work to have the RTL writer give us something more useful.
>>  That
>> may mean simple changes to the output, or some conditional changes
>> (like
>> not emitting the INSN_CODE or its name).
>
> That would make the reader a lot less grim; it has a lot of warts for
> dealing with all the special cases in the current output format.
That's the idea.

>
> But maybe it is useful to be able to deal with the current output
> format.  For example, I was able to look at PR 71779 and find some
> fragmentary RTL dumps there (comment #2) and use them.  I *did* need to
> edit them a little, so maybe it's OK to require a little editing
> (especially with older dumps... to what extent has the format changed
> over the years?)
It's changed, but not in radical ways.

I think the case we want to cater to is dumping something from the 
current compiler rather than picking up some crusty RTL and creating a 
testcase from that.  By "current" I explicitly want the ability to 
refine the output to make the reader easier to implement.

Jeff

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

* Re: [PATCH 8/9] final.c selftests
  2016-09-16 21:41     ` David Malcolm
@ 2016-09-19 21:38       ` Jeff Law
  0 siblings, 0 replies; 56+ messages in thread
From: Jeff Law @ 2016-09-19 21:38 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/16/2016 03:34 PM, David Malcolm wrote:
> On Fri, 2016-09-16 at 14:45 -0600, Jeff Law wrote:
>> On 09/08/2016 06:30 PM, David Malcolm wrote:
>>> gcc/ChangeLog:
>>> 	* final.c: Include selftest.h and selftest-rtl.h.
>>> 	(class selftest::temp_asm_out): New subclass of
>>> 	selftest::named_temp_file.
>>> 	(selftest::temp_asm_out::temp_asm_out): New ctor.
>>> 	(selftest::temp_asm_out::~temp_asm_out): New dtor.
>>> 	(class selftest::asm_out_test): New subclass of
>>> 	selftest::rtl_dump_test.
>>> 	(selftest::asm_out_test::asm_out_test): New ctor.
>>> 	(selftest::test_jump_insn): New function.
>>> 	(selftest::test_empty_function): New function.
>>> 	(selftest::test_asm_for_insn): New function.
>>> 	(TEST_ASM_FOR_INSN): New macro.
>>> 	(selftest::test_x86_64_leal): New function.
>>> 	(selftest::test_x86_64_negl): New function.
>>> 	(selftest::test_x86_64_cmpl): New function.
>>> 	(selftest::test_x86_64_cmovge): New function.
>>> 	(selftest::test_x86_64_ret): New function.
>>> 	(selftest::final_c_tests): New function.
>>> 	* selftest-run-tests.c (selftest::run_tests): Call
>>> 	selftest::final_c_tests.
>>> 	* selftest.h (selftest::final_c_tests): New decl.
>> I'm really not sure how useful these tests are going to be and would
>> question the long term maintenance costs of keeping them up-to-date.
>>
>> I could see perhaps verifying that when there are multiple
>> alternatives
>> that the correct one is selected or somesuch, but these tests really
>> don't seem to be covering anything particularly useful.
>
> My thinking here was that it might be useful to verify insn recognition
> and output when someone is bringing up a new target, or adding new
> insns to a .md file; the selftest::test_x86_64_cmpl show the beginnings
> of how one might write that in selftest form.
Understood.  I'm just not sure how helpful that will be in practice and 
it seems like a maintenance nightmare.

The case where I think something like this is useful is when there's 
multiple ways to express the same insn and there's a preferred form. 
Say because the preferred form is smaller, faster, whatever.

But even that can be incredibly painful.  Consider zero-ing a register 
on the x86.  There's mov 0,reg; xor reg, reg; sub reg,reg, etc.  Which 
is preferred depends on the micro-architecture and possibly surrounding 
context, whether or not the containing block is hot or not, etc.


>
> But I'm happy to drop it.
I don't think it buys us much right now.  It is archived if we end up 
changing our minds.

jeff

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

* Re: [PATCH 5/9] Introduce class function_reader
  2016-09-16 22:04     ` David Malcolm
@ 2016-09-19 21:39       ` Jeff Law
  0 siblings, 0 replies; 56+ messages in thread
From: Jeff Law @ 2016-09-19 21:39 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/16/2016 03:42 PM, David Malcolm wrote:
> On Fri, 2016-09-16 at 15:28 -0600, Jeff Law wrote:
>> On 09/08/2016 06:30 PM, David Malcolm wrote:
>>> 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.
>>
>>> 	* cfgexpand.c (pass_expand::execute): Move stack
>>> initializations
>>> 	to rtl_data::init_stack_alignment and call it.  Pass "true"
>>> 	for new "emit_insns" param of expand_function_start.
>>> 	* 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.
>>> 	(rtl_data::init_stack_alignment): New method.
>>> 	(get_insn_by_uid): New function.
>>> 	* emit-rtl.h (rtl_data::init_stack_alignment): New method.
>>> 	* 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)).
>>> 	(expand_function_start): Add param "emit_insns", and use it to
>>> 	guard the various gen/emit calls.
>>> 	* function.h (emit_status::ensure_regno_capacity): New method.
>>> 	(expand_function_start): Add bool param to decl.
>>> 	* gensupport.c (gen_reader::gen_reader): Add NULL for new
>>> policy
>>> 	param of rtx_reader ctor.
>>> 	* 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 '/'.
>>> 	(require_char): New function.
>>> 	(require_word_ws): New function.
>>> 	(peek_char): New function.
>>> 	(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.  */
>>> 	(rtx_reader::rtx_reader): Add rtl_reader_policy * param, using
>>> 	it to initialize m_policy.
>>> 	(rtx_reader::~rtx_reader): Free m_base_dir.  Clean up global
>>> data.
>>> 	* read-md.h (struct file_location): Move to errors.h.
>>> 	(file_location::file_location): Likewise.
>>> 	Include errors.h.
>>> 	(class regno_remapper): New class.
>>> 	(struct rtl_reader_policy): New struct.
>>> 	(rtx_reader::rtx_reader): Add rtl_reader_policy * param.
>>> 	(rtx_reader::add_fixup_insn_uid): New vfunc.
>>> 	(rtx_reader::add_fixup_bb): New vfunc.
>>> 	(rtx_reader::add_fixup_note_insn_basic_block): New vfunc.
>>> 	(rtx_reader::add_fixup_source_location): New vfunc.
>>> 	(rtx_reader::add_fixup_jump_label): New vfunc.
>>> 	(rtx_reader::add_fixup_expr): New vfunc.
>>> 	(rtx_reader::remap_regno): New method.
>>> 	(rtx_reader::m_policy): New field.
>>> 	(noop_reader::noop_reader): Add NULL for new policy param of
>>> 	rtx_reader ctor.
>>> 	(peek_char): New decl.
>>> 	(require_char): New decl.
>>> 	(require_word_ws): New decl.
>>> 	(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.
>>> 	(read_rtx): Likewise.  Move one-time initialization logic to...
>>> 	(one_time_initialization): New function.
>>> 	(parse_reg_note_name): New function.
>>> 	(parse_note_insn_name): New function.
>>> 	(maybe_read_location): New function.
>>> 	(read_until): New function.
>>> 	(strip_trailing_whitespace): New function.
>>> 	(read_flags): New function.
>>> 	(regno_remapper::get_effective_regno): New method.
>>> 	(rtx_reader::remap_regno): New method.
>>> 	(read_rtx_code): Remove "static".  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 SYMBOL_REF data, REG_NOTE names,
>>> 	INSN_UID values, note-specific data, basic block IDs,
>>> 	jump labels, hexdump values of wide ints, REG_EXPR, MEM_EXPR,
>>> 	skipping recognized insn names, remapping register numbers.
>>> 	When on host, reallocate XSTR and XTMPL fields in the GC
>>> -managed
>>> 	heap.
>>> 	(lookup_global_register): New function.
>>> 	(consolidate_reg): New function.
>>> 	(consolidate_singletons): New function.
>>> 	(read_nested_rtx): Call consolidate_singletons.
>>> 	* rtl.h (read_rtx): Wrap decl with #ifdef GENERATOR_FILE.
>>> 	(read_rtx_code): New decl.
>>> 	* 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.
>> So I see a couple conceptual things going on here.
>>
>> First is initialization/finalization/state handling and various
>> fallout
>> items.  Essentially it encompasses all changes that we can make a
>> case
>> are useful cleanups and should be handled independently.
>
> I think you've described patch 1 of the kit :)
There were things in #5 that seemed like they ought to have been pulled 
out as separate cleanups.  Just as an example, look at the changes to 
cfgexpand.c.  There were others.


Jeff

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

* Register numbers in RTL dumps (was Re: [PATCH 0/9] RFC: selftests based on RTL dumps)
  2016-09-19 17:50           ` Jeff Law
@ 2016-09-20 14:34             ` David Malcolm
  2016-09-20 14:38               ` Bernd Schmidt
  0 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-20 14:34 UTC (permalink / raw)
  To: Jeff Law, Bernd Schmidt, gcc-patches

On Mon, 2016-09-19 at 11:35 -0600, Jeff Law wrote:
> On 09/16/2016 03:27 PM, David Malcolm wrote:
> > > We should also twiddle how we represent registers in the dumps.
> > > Identifying hard regs by name (so we can map back to a hard reg
> > > if
> > > the
> > > hard regs change), identifying pseudos by number that isn't
> > > affected
> > > if
> > > the hard register set changes ie, p0, p1, p2, p3 where the number
> > > is
> > > REGNO (x) - FIRST_PSEUDO_REGISTER. identifying the virtual
> > > registers,
> > > etc.
> > 
> > Good idea.
> > 
> > I don't know if you saw this yet, but the patch has logic from
> > renumbering pseudos on load (see class regno_remapper), but dumping
> > them as p0, p1 etc and reloading them as such seems much easier for
> > everyone.
> And just an FYI, I think we should do this unconditionally in our
> dumps.

To summarize so far: you want every pseudo to have its regno dumped
with a 'p' prefix, and renumber them on dump (and then on load).
OK.

When dumping regnos, would you want another distinction between
virtuals and non-virtuals in the dump?  For example, given that
LAST_VIRTUAL_POINTER_REGISTER is ((FIRST_VIRTUAL_REGISTER) + 4), this
could mean:

  v0, v1, ..., v4  for the virtual regnos

and, for pseudos that aren't virtual regnos:
  p0, p1, ...
or
  p5, p6, ...
depending on whether we want to start numbering the pseudos at p0 for
LAST_VIRTUAL_REGISTER + 1, or whether we regard v0 as the first pseduo,
and hence p5 is the first non-virtual pseudo.   FWIW I think starting
at p5 is the better approach, given that:
  #define FIRST_VIRTUAL_REGISTER	(FIRST_PSEUDO_REGISTER)

Either way, this would give things like:
  (reg/f:DI v1 virtual-stack-vars)
  (reg:DI p78)

In a similar vein, how about adding a "h" prefix for the hard regnos?
That way every regno would have a one-char prefix telling you what kind
of reg it is (and you can directly see whether or not you need to
offset the number by FIRST_PSEUDO_REGISTER to get at the "real" regno).

This would give things (for x86_64) like:
  (reg/i:SI h0 ax)
  (reg/i:SF h21 xmm0)

> > 
> > > The key being rather than put a ton of smarts/hacks in a reader,
> > > we
> > > should work to have the RTL writer give us something more useful.
> > >  That
> > > may mean simple changes to the output, or some conditional
> > > changes
> > > (like
> > > not emitting the INSN_CODE or its name).
> > 
> > That would make the reader a lot less grim; it has a lot of warts
> > for
> > dealing with all the special cases in the current output format.
> That's the idea.
> > 
> > But maybe it is useful to be able to deal with the current output
> > format.  For example, I was able to look at PR 71779 and find some
> > fragmentary RTL dumps there (comment #2) and use them.  I *did*
> > need to
> > edit them a little, so maybe it's OK to require a little editing
> > (especially with older dumps... to what extent has the format
> > changed
> > over the years?)
> It's changed, but not in radical ways.
> 
> I think the case we want to cater to is dumping something from the 
> current compiler rather than picking up some crusty RTL and creating
> a 
> testcase from that.  By "current" I explicitly want the ability to 
> refine the output to make the reader easier to implement.
> 
> Jeff

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

* Re: Register numbers in RTL dumps (was Re: [PATCH 0/9] RFC: selftests based on RTL dumps)
  2016-09-20 14:34             ` Register numbers in RTL dumps (was Re: [PATCH 0/9] RFC: selftests based on RTL dumps) David Malcolm
@ 2016-09-20 14:38               ` Bernd Schmidt
  2016-09-20 15:26                 ` Jeff Law
  0 siblings, 1 reply; 56+ messages in thread
From: Bernd Schmidt @ 2016-09-20 14:38 UTC (permalink / raw)
  To: David Malcolm, Jeff Law, gcc-patches

On 09/20/2016 04:32 PM, David Malcolm wrote:
>
> To summarize so far: you want every pseudo to have its regno dumped
> with a 'p' prefix, and renumber them on dump (and then on load).
> OK.

Renumbering is not helpful because it interferes with the view you have 
in the debugger. So, IMO just a prefix, and maybe

>   (reg/f:DI v1 virtual-stack-vars)

this.


Bernd

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

* Re: Register numbers in RTL dumps (was Re: [PATCH 0/9] RFC: selftests based on RTL dumps)
  2016-09-20 14:38               ` Bernd Schmidt
@ 2016-09-20 15:26                 ` Jeff Law
  2016-09-20 15:38                   ` Bernd Schmidt
  2016-09-20 19:35                   ` David Malcolm
  0 siblings, 2 replies; 56+ messages in thread
From: Jeff Law @ 2016-09-20 15:26 UTC (permalink / raw)
  To: Bernd Schmidt, David Malcolm, gcc-patches

On 09/20/2016 08:34 AM, Bernd Schmidt wrote:
> On 09/20/2016 04:32 PM, David Malcolm wrote:
>>
>> To summarize so far: you want every pseudo to have its regno dumped
>> with a 'p' prefix, and renumber them on dump (and then on load).
>> OK.
>
> Renumbering is not helpful because it interferes with the view you have
> in the debugger. So, IMO just a prefix, and maybe
Yea, I guess it does since we want the numbers in the dump to be the 
same that we used to access the arrays.  So prefixing in the dump with 
adjustment of the number in the reader.

>
>>   (reg/f:DI v1 virtual-stack-vars)
>
> this.
Doesn't the same apply to the number of virtual stack regs?  Those are 
in the same array as pseudos.  So ISTM we prefix in the dump, but do 
adjustment of the number in the reader?

jeff

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

* Re: Register numbers in RTL dumps (was Re: [PATCH 0/9] RFC: selftests based on RTL dumps)
  2016-09-20 15:26                 ` Jeff Law
@ 2016-09-20 15:38                   ` Bernd Schmidt
  2016-09-20 19:35                   ` David Malcolm
  1 sibling, 0 replies; 56+ messages in thread
From: Bernd Schmidt @ 2016-09-20 15:38 UTC (permalink / raw)
  To: Jeff Law, David Malcolm, gcc-patches

On 09/20/2016 05:20 PM, Jeff Law wrote:
> On 09/20/2016 08:34 AM, Bernd Schmidt wrote:

>>>   (reg/f:DI v1 virtual-stack-vars)
>>
>> this.
> Doesn't the same apply to the number of virtual stack regs?  Those are
> in the same array as pseudos.  So ISTM we prefix in the dump, but do
> adjustment of the number in the reader?

I meant the virtual-stack-vars name. But maybe we're already doing that, 
I can't remember.


Bernd

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

* Re: Register numbers in RTL dumps (was Re: [PATCH 0/9] RFC: selftests based on RTL dumps)
  2016-09-20 15:26                 ` Jeff Law
  2016-09-20 15:38                   ` Bernd Schmidt
@ 2016-09-20 19:35                   ` David Malcolm
  2016-09-21 18:59                     ` [PATCH] print-rtx.c: add 'h', v' and 'p' prefixes to regnos David Malcolm
  1 sibling, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-20 19:35 UTC (permalink / raw)
  To: Jeff Law, Bernd Schmidt, gcc-patches

On Tue, 2016-09-20 at 09:20 -0600, Jeff Law wrote:
> On 09/20/2016 08:34 AM, Bernd Schmidt wrote:
> > On 09/20/2016 04:32 PM, David Malcolm wrote:
> > > 
> > > To summarize so far: you want every pseudo to have its regno
> > > dumped
> > > with a 'p' prefix, and renumber them on dump (and then on load).
> > > OK.
> > 
> > Renumbering is not helpful because it interferes with the view you
> > have
> > in the debugger. So, IMO just a prefix, and maybe
> Yea, I guess it does since we want the numbers in the dump to be the 
> same that we used to access the arrays.  So prefixing in the dump
> with 
> adjustment of the number in the reader.

To check I understand: am I right in thinking you want:
(A) the numbers in the dump to be unmodified when dumping, so that we
can easily look up values in arrays without confusion, and
(B) regnums in the dump gain a 'p' prefix for values >=
 FIRST_PSEUDO_REGISTER, so that humans and parsers can easily see when
the regs are pseudos, and that
(C) the parser will detect if a 'p'-prefixed regno actually has the
same number as a hard reg (which can happen e.g. when a .md file
changes, or when sharing .rtl dumps between targets), and remap the
values on load accordingly

?

(in which case we do need the regno_remapper class, or something like
it)

> > 
> > >   (reg/f:DI v1 virtual-stack-vars)
> > 
> > this.
> Doesn't the same apply to the number of virtual stack regs?  Those
> are 
> in the same array as pseudos.  So ISTM we prefix in the dump, but do 
> adjustment of the number in the reader?

Presumably we could use "v" rather than "p" as the prefix for the first
5 pseudos (up to LAST_VIRTUAL_REGISTER), doing any adjustment at load
time, rather than at dump time.  So the above example would look like:

   (reg/f:DI v82 virtual-stack-vars)

i.e. the 82 for x86_64's virtual-stack-vars would be prefixed with a
'v', and the loader would adjust it to be the current target's value
for VIRTUAL_STACK_VARS_REGNUM.

Do you like the idea of prefixing regnums of hardregs with 'h'? (so
that all regnos get a one-char prefix) e.g.
  (reg/i:SI h0 ax)
  (reg/i:SF h21 xmm0)


Dave

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

* [PATCH, v2] Introduce class rtx_reader
  2016-09-16 22:15   ` Jeff Law
@ 2016-09-21 17:22     ` David Malcolm
  2016-09-21 20:44       ` Richard Sandiford
  0 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-21 17:22 UTC (permalink / raw)
  To: Jeff Law, gcc-patches, Richard Sandiford; +Cc: David Malcolm

On Fri, 2016-09-16 at 16:04 -0600, Jeff Law wrote:
> On 09/08/2016 06:30 PM, David Malcolm wrote:
> > Bundle up various global variables within gensupport.c into a
> > class rtx_reader, with a view towards making it easier to run the
> > code more than once in-process.
> > 
> > gcc/ChangeLog:
> > 	* genconstants.c (main): Introduce noop_reader and convert call
> > 	to read_md_files to a method call.
> > 	* genenums.c (main): Likewise.
> > 	* genmddeps.c (main): Likewise.
> > 	* genpreds.c (write_tm_constrs_h): Replace use of "in_fname"
> > with
> > 	rtx_reader_ptr->get_top_level_filename ().
> > 	(write_tm_preds_h): Likewise.
> > 	(write_insn_preds_c): Likewise.
> > 	* gensupport.c (class gen_reader): New subclass of rtx_reader.
> > 	(rtx_handle_directive): Convert to...
> > 	(gen_reader::handle_unknown_directive): ...this.
> > 	(init_rtx_reader_args_cb): Convert return type from bool to
> > 	rtx_reader *.  Create a gen_reader instance, using it for the
> > 	call to read_md_files.  Return it if no errors occur.
> > 	(init_rtx_reader_args): Convert return type from bool to
> > 	rtx_reader *.
> > 	* gensupport.h (init_rtx_reader_args_cb): Likewise.
> > 	(init_rtx_reader_args_cb): Likewise.
> > 	* read-md.c (struct file_name_list): Move to class rtx_reader.
> > 	(read_md_file): Delete in favor of rtx_reader::m_read_md_file.
> > 	(read_md_filename): Delete in favor of
> > 	rtx_reader::m_read_md_filename.
> > 	(read_md_lineno): Delete in favor of
> > rtx_reader::m_read_md_lineno.
> > 	(in_fname): Delete in favor of rtx_reader::m_toplevel_fname.
> > 	(base_dir): Delete in favor of rtx_reader::m_base_dir.
> > 	(first_dir_md_include): Delete in favor of
> > 	rtx_reader::m_first_dir_md_include.
> > 	(last_dir_md_include_ptr): Delete in favor of
> > 	rtx_reader::m_last_dir_md_include_ptr.
> > 	(max_include_len): Delete.
> > 	(rtx_reader_ptr): New.
> > 	(fatal_with_file_and_line): Use get_filename and get_lineno
> > 	accessors of rtx_reader_ptr.
> > 	(require_char_ws): Likewise.
> > 	(rtx_reader::read_char): New method, based on ::read_char.
> > 	(rtx_reader::unread_char): New method, based on ::unread_char.
> > 	(read_escape): Use get_filename and get_lineno accessors of
> > 	rtx_reader_ptr.
> > 	(read_braced_string): Use get_lineno accessor of
> > rtx_reader_ptr.
> > 	(read_string): Use get_filename and get_lineno accessors of
> > 	rtx_reader_ptr.
> > 	(rtx_reader::rtx_reader): New ctor.
> > 	(rtx_reader::~rtx_reader): New dtor.
> > 	(handle_include): Convert from a function to...
> > 	(rtx_reader::handle_include): ...this method, converting
> > 	handle_directive from a callback to a virtual function.
> > 	(handle_file): Likewise, converting to...
> > 	(rtx_reader::handle_file): ...this method.
> > 	(handle_toplevel_file): Likewise, converting to...
> > 	(rtx_reader::handle_toplevel_file): ...this method.
> > 	(rtx_reader::get_current_location): New method.
> > 	(parse_include): Convert from a function to...
> > 	(rtx_reader::add_include_path): ...this method, dropping
> > redundant
> > 	update to unused max_include_len.
> > 	(read_md_files): Convert from a function to...
> > 	(rtx_reader::read_md_files): ...this method, converting
> > 	handle_directive from a callback to a virtual function.
> > 	(noop_reader::handle_unknown_directive): New method.
> > 	* read-md.h (directive_handler_t): Delete this typedef.
> > 	(in_fname): Delete.
> > 	(read_md_file): Delete.
> > 	(read_md_lineno): Delete.
> > 	(read_md_filename): Delete.
> > 	(class rtx_reader): New class.
> > 	(rtx_reader_ptr): New decl.
> > 	(class noop_reader): New subclass of rtx_reader.
> > 	(read_char): Reimplement in terms of rtx_reader::read_char.
> > 	(unread_char): Reimplement in terms of rtx_reader::unread_char.
> > 	(read_md_files): Delete.
> > 	* read-rtl.c (read_rtx_code): Update for deletion of globals
> > 	read_md_filename and read_md_lineno.
> I don't see anything terribly objectionable here.
> 
> It looks like you use a singleton to avoid passing the object around
> everywhere, but given the state of all this prior to this patch, I
> can
> live with the cleanup as a whole.

Indeed; the point of the patch is to bundle up some global state to
better allow the reader to be run more than once in-process, so that
the RTL frontend can have selftests; having more than one reader *alive*
at once is out-of-scope.  Hence the use of a singleton, to minimize the
amount of churn.

> I'll note Richard Sandiford. hasn't chimed in here.  You might ping
> him
> directly to see if he's got any feedback.  If he doesn't prior to say
> Wed, this is OK for the trunk.
> 
> jeff

Thanks.

Here's a slightly tweaked version, fixing a couple of missing NULL
initializations in the rtx_reader ctor (of m_base_dir and m_read_md_file),
which avoids a crash for the file-not-found case.

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

Richard: do you have any feedback on this?
Otherwise, I'll assume this is still OK for trunk in a few days.

gcc/ChangeLog:
	* genconstants.c (main): Introduce noop_reader and convert call
	to read_md_files to a method call.
	* genenums.c (main): Likewise.
	* genmddeps.c (main): Likewise.
	* genpreds.c (write_tm_constrs_h): Replace use of "in_fname" with
	rtx_reader_ptr->get_top_level_filename ().
	(write_tm_preds_h): Likewise.
	(write_insn_preds_c): Likewise.
	* gensupport.c (class gen_reader): New subclass of rtx_reader.
	(rtx_handle_directive): Convert to...
	(gen_reader::handle_unknown_directive): ...this.
	(init_rtx_reader_args_cb): Convert return type from bool to
	rtx_reader *.  Create a gen_reader instance, using it for the
	call to read_md_files.  Return it if no errors occur.
	(init_rtx_reader_args): Convert return type from bool to
	rtx_reader *.
	* gensupport.h (init_rtx_reader_args_cb): Likewise.
	(init_rtx_reader_args_cb): Likewise.
	* read-md.c (struct file_name_list): Move to class rtx_reader.
	(read_md_file): Delete in favor of rtx_reader::m_read_md_file.
	(read_md_filename): Delete in favor of
	rtx_reader::m_read_md_filename.
	(read_md_lineno): Delete in favor of rtx_reader::m_read_md_lineno.
	(in_fname): Delete in favor of rtx_reader::m_toplevel_fname.
	(base_dir): Delete in favor of rtx_reader::m_base_dir.
	(first_dir_md_include): Delete in favor of
	rtx_reader::m_first_dir_md_include.
	(last_dir_md_include_ptr): Delete in favor of
	rtx_reader::m_last_dir_md_include_ptr.
	(max_include_len): Delete.
	(rtx_reader_ptr): New.
	(fatal_with_file_and_line): Use get_filename and get_lineno
	accessors of rtx_reader_ptr.
	(require_char_ws): Likewise.
	(rtx_reader::read_char): New method, based on ::read_char.
	(rtx_reader::unread_char): New method, based on ::unread_char.
	(read_escape): Use get_filename and get_lineno accessors of
	rtx_reader_ptr.
	(read_braced_string): Use get_lineno accessor of rtx_reader_ptr.
	(read_string): Use get_filename and get_lineno accessors of
	rtx_reader_ptr.
	(rtx_reader::rtx_reader): New ctor.
	(rtx_reader::~rtx_reader): New dtor.
	(handle_include): Convert from a function to...
	(rtx_reader::handle_include): ...this method, converting
	handle_directive from a callback to a virtual function.
	(handle_file): Likewise, converting to...
	(rtx_reader::handle_file): ...this method.
	(handle_toplevel_file): Likewise, converting to...
	(rtx_reader::handle_toplevel_file): ...this method.
	(rtx_reader::get_current_location): New method.
	(parse_include): Convert from a function to...
	(rtx_reader::add_include_path): ...this method, dropping redundant
	update to unused max_include_len.
	(read_md_files): Convert from a function to...
	(rtx_reader::read_md_files): ...this method, converting
	handle_directive from a callback to a virtual function.
	(noop_reader::handle_unknown_directive): New method.
	* read-md.h (directive_handler_t): Delete this typedef.
	(in_fname): Delete.
	(read_md_file): Delete.
	(read_md_lineno): Delete.
	(read_md_filename): Delete.
	(class rtx_reader): New class.
	(rtx_reader_ptr): New decl.
	(class noop_reader): New subclass of rtx_reader.
	(read_char): Reimplement in terms of rtx_reader::read_char.
	(unread_char): Reimplement in terms of rtx_reader::unread_char.
	(read_md_files): Delete.
	* read-rtl.c (read_rtx_code): Update for deletion of globals
	read_md_filename and read_md_lineno.
---
 gcc/genconstants.c |   3 +-
 gcc/genenums.c     |   3 +-
 gcc/genmddeps.c    |   3 +-
 gcc/genpreds.c     |   9 ++-
 gcc/gensupport.c   |  29 +++++--
 gcc/gensupport.h   |   6 +-
 gcc/read-md.c      | 227 ++++++++++++++++++++++++++++++-----------------------
 gcc/read-md.h      |  98 ++++++++++++++++++-----
 gcc/read-rtl.c     |   3 +-
 9 files changed, 244 insertions(+), 137 deletions(-)

diff --git a/gcc/genconstants.c b/gcc/genconstants.c
index c10e3e3..e8be5b6 100644
--- a/gcc/genconstants.c
+++ b/gcc/genconstants.c
@@ -79,7 +79,8 @@ main (int argc, const char **argv)
 {
   progname = "genconstants";
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return (FATAL_EXIT_CODE);
 
   /* Initializing the MD reader has the side effect of loading up
diff --git a/gcc/genenums.c b/gcc/genenums.c
index db46a67..8af8d9a 100644
--- a/gcc/genenums.c
+++ b/gcc/genenums.c
@@ -49,7 +49,8 @@ main (int argc, const char **argv)
 {
   progname = "genenums";
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return (FATAL_EXIT_CODE);
 
   puts ("/* Generated automatically by the program `genenums'");
diff --git a/gcc/genmddeps.c b/gcc/genmddeps.c
index fd26a33..e3d229d 100644
--- a/gcc/genmddeps.c
+++ b/gcc/genmddeps.c
@@ -47,7 +47,8 @@ main (int argc, const char **argv)
   progname = "genmddeps";
   include_callback = add_filedep;
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return FATAL_EXIT_CODE;
 
   *last = NULL;
diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index 4c9dfc6..96f75bd 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -1204,7 +1204,8 @@ write_tm_constrs_h (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_CONSTRS_H\n\
@@ -1403,7 +1404,8 @@ write_tm_preds_h (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_PREDS_H\n\
@@ -1552,7 +1554,8 @@ write_insn_preds_c (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #include \"config.h\"\n\
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index 4645ead..1648c9c 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2225,10 +2225,18 @@ process_define_subst (void)
     }
 }
 \f
-/* A read_md_files callback for reading an rtx.  */
+/* A subclass of rtx_reader which reads .md files and calls process_rtx on
+   the top-level elements.  */
 
-static void
-rtx_handle_directive (file_location loc, const char *rtx_name)
+class gen_reader : public rtx_reader
+{
+ public:
+  gen_reader () : rtx_reader () {}
+  void handle_unknown_directive (file_location, const char *);
+};
+
+void
+gen_reader::handle_unknown_directive (file_location loc, const char *rtx_name)
 {
   auto_vec<rtx, 32> subrtxs;
   if (!read_rtx (rtx_name, &subrtxs))
@@ -2499,7 +2507,7 @@ check_define_attr_duplicates ()
 
 /* The entry point for initializing the reader.  */
 
-bool
+rtx_reader *
 init_rtx_reader_args_cb (int argc, const char **argv,
 			 bool (*parse_opt) (const char *))
 {
@@ -2515,7 +2523,8 @@ init_rtx_reader_args_cb (int argc, const char **argv,
   split_sequence_num = 1;
   peephole2_sequence_num = 1;
 
-  read_md_files (argc, argv, parse_opt, rtx_handle_directive);
+  gen_reader *reader = new gen_reader ();
+  reader->read_md_files (argc, argv, parse_opt);
 
   if (define_attr_queue != NULL)
     check_define_attr_duplicates ();
@@ -2531,12 +2540,18 @@ init_rtx_reader_args_cb (int argc, const char **argv,
   if (define_attr_queue != NULL)
     gen_mnemonic_attr ();
 
-  return !have_error;
+  if (have_error)
+    {
+      delete reader;
+      return NULL;
+    }
+
+  return reader;
 }
 
 /* Programs that don't have their own options can use this entry point
    instead.  */
-bool
+rtx_reader *
 init_rtx_reader_args (int argc, const char **argv)
 {
   return init_rtx_reader_args_cb (argc, argv, 0);
diff --git a/gcc/gensupport.h b/gcc/gensupport.h
index 645512c..618359d 100644
--- a/gcc/gensupport.h
+++ b/gcc/gensupport.h
@@ -125,9 +125,9 @@ struct optab_pattern
 };
 
 extern rtx add_implicit_parallel (rtvec);
-extern bool init_rtx_reader_args_cb (int, const char **,
-				     bool (*)(const char *));
-extern bool init_rtx_reader_args (int, const char **);
+extern rtx_reader *init_rtx_reader_args_cb (int, const char **,
+					    bool (*)(const char *));
+extern rtx_reader *init_rtx_reader_args (int, const char **);
 extern bool read_md_rtx (md_rtx_info *);
 extern unsigned int get_num_insn_codes ();
 
diff --git a/gcc/read-md.c b/gcc/read-md.c
index b422d8d..f069ba5 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -31,12 +31,6 @@ struct ptr_loc {
   int lineno;
 };
 
-/* A singly-linked list of filenames.  */
-struct file_name_list {
-  struct file_name_list *next;
-  const char *fname;
-};
-
 /* Obstack used for allocating MD strings.  */
 struct obstack string_obstack;
 
@@ -56,34 +50,13 @@ static htab_t joined_conditions;
 /* An obstack for allocating joined_conditions entries.  */
 static struct obstack joined_conditions_obstack;
 
-/* The file we are reading.  */
-FILE *read_md_file;
-
-/* The filename of READ_MD_FILE.  */
-const char *read_md_filename;
-
-/* The current line number in READ_MD_FILE.  */
-int read_md_lineno;
-
-/* The name of the toplevel file that indirectly included READ_MD_FILE.  */
-const char *in_fname;
-
-/* The directory part of IN_FNAME.  NULL if IN_FNAME is a bare filename.  */
-static char *base_dir;
-
-/* The first directory to search.  */
-static struct file_name_list *first_dir_md_include;
-
-/* A pointer to the null terminator of the md include chain.  */
-static struct file_name_list **last_dir_md_include_ptr = &first_dir_md_include;
-
 /* 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 *);
 
-/* The current maximum length of directory names in the search path
-   for include files.  (Altered as we get more of them.)  */
-static size_t max_include_len;
+/* Global singleton.  */
+
+rtx_reader *rtx_reader_ptr;
 
 /* A table of md_constant structures, hashed by name.  Null if no
    constant expansion should occur.  */
@@ -92,8 +65,6 @@ static htab_t md_constants;
 /* A table of enum_type structures, hashed by name.  */
 static htab_t enum_types;
 
-static void handle_file (directive_handler_t);
-
 /* Given an object that starts with a char * name field, return a hash
    code for its name.  */
 
@@ -303,7 +274,8 @@ fatal_with_file_and_line (const char *msg, ...)
 
   va_start (ap, msg);
 
-  fprintf (stderr, "%s:%d: ", read_md_filename, read_md_lineno);
+  fprintf (stderr, "%s:%d: error: ", rtx_reader_ptr->get_filename (),
+	   rtx_reader_ptr->get_lineno ());
   vfprintf (stderr, msg, ap);
   putc ('\n', stderr);
 
@@ -322,8 +294,9 @@ fatal_with_file_and_line (const char *msg, ...)
     }
   context[i] = '\0';
 
-  fprintf (stderr, "%s:%d: following context is `%s'\n",
-	   read_md_filename, read_md_lineno, context);
+  fprintf (stderr, "%s:%d: note: following context is `%s'\n",
+	   rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+	   context);
 
   va_end (ap);
   exit (1);
@@ -402,6 +375,30 @@ require_char_ws (char expected)
     fatal_expected_char (expected, ch);
 }
 
+/* Read the next character from the file.  */
+
+int
+rtx_reader::read_char (void)
+{
+  int ch;
+
+  ch = getc (m_read_md_file);
+  if (ch == '\n')
+    m_read_md_lineno++;
+
+  return ch;
+}
+
+/* Put back CH, which was the last character read from the file.  */
+
+void
+rtx_reader::unread_char (int ch)
+{
+  if (ch == '\n')
+    m_read_md_lineno--;
+  ungetc (ch, m_read_md_file);
+}
+
 /* Read an rtx code name into NAME.  It is terminated by any of the
    punctuation chars of rtx printed syntax.  */
 
@@ -512,7 +509,8 @@ read_escape (void)
       /* pass anything else through, but issue a warning.  */
     default:
       fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
-	       read_md_filename, read_md_lineno, c);
+	       rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+	       c);
       obstack_1grow (&string_obstack, '\\');
       break;
     }
@@ -555,7 +553,7 @@ read_braced_string (void)
 {
   int c;
   int brace_depth = 1;  /* caller-processed */
-  unsigned long starting_read_md_lineno = read_md_lineno;
+  unsigned long starting_read_md_lineno = rtx_reader_ptr->get_lineno ();
 
   obstack_1grow (&string_obstack, '{');
   while (brace_depth)
@@ -601,7 +599,7 @@ read_string (int star_if_braced)
       c = read_skip_spaces ();
     }
 
-  old_lineno = read_md_lineno;
+  old_lineno = rtx_reader_ptr->get_lineno ();
   if (c == '"')
     stringbuf = read_quoted_string ();
   else if (c == '{')
@@ -616,7 +614,7 @@ read_string (int star_if_braced)
   if (saw_paren)
     require_char_ws (')');
 
-  set_md_ptr_loc (stringbuf, read_md_filename, old_lineno);
+  set_md_ptr_loc (stringbuf, rtx_reader_ptr->get_filename (), old_lineno);
   return stringbuf;
 }
 
@@ -901,13 +899,37 @@ traverse_enum_types (htab_trav callback, void *info)
   htab_traverse (enum_types, callback, info);
 }
 
+
+/* Constructor for rtx_reader.  */
+
+rtx_reader::rtx_reader ()
+: m_toplevel_fname (NULL),
+  m_base_dir (NULL),
+  m_read_md_file (NULL),
+  m_read_md_filename (NULL),
+  m_read_md_lineno (0),
+  m_first_dir_md_include (NULL),
+  m_last_dir_md_include_ptr (&m_first_dir_md_include)
+{
+  /* Set the global singleton pointer.  */
+  rtx_reader_ptr = this;
+}
+
+/* rtx_reader's destructor.  */
+
+rtx_reader::~rtx_reader ()
+{
+  /* Clear the global singleton pointer.  */
+  rtx_reader_ptr = NULL;
+}
+
 /* Process an "include" directive, starting with the optional space
    after the "include".  Read in the file and use HANDLE_DIRECTIVE
    to process each unknown directive.  LINENO is the line number on
    which the "include" occurred.  */
 
-static void
-handle_include (file_location loc, directive_handler_t handle_directive)
+void
+rtx_reader::handle_include (file_location loc)
 {
   const char *filename;
   const char *old_filename;
@@ -924,7 +946,7 @@ handle_include (file_location loc, directive_handler_t handle_directive)
       struct file_name_list *stackp;
 
       /* Search the directory path, trying to open the file.  */
-      for (stackp = first_dir_md_include; stackp; stackp = stackp->next)
+      for (stackp = m_first_dir_md_include; stackp; stackp = stackp->next)
 	{
 	  static const char sep[2] = { DIR_SEPARATOR, '\0' };
 
@@ -940,8 +962,8 @@ handle_include (file_location loc, directive_handler_t handle_directive)
      filename with BASE_DIR.  */
   if (input_file == NULL)
     {
-      if (base_dir)
-	pathname = concat (base_dir, filename, NULL);
+      if (m_base_dir)
+	pathname = concat (m_base_dir, filename, NULL);
       else
 	pathname = xstrdup (filename);
       input_file = fopen (pathname, "r");
@@ -957,21 +979,22 @@ handle_include (file_location loc, directive_handler_t handle_directive)
   /* Save the old cursor.  Note that the LINENO argument to this
      function is the beginning of the include statement, while
      read_md_lineno has already been advanced.  */
-  old_file = read_md_file;
-  old_filename = read_md_filename;
-  old_lineno = read_md_lineno;
+  old_file = m_read_md_file;
+  old_filename = m_read_md_filename;
+  old_lineno = m_read_md_lineno;
 
   if (include_callback)
     include_callback (pathname);
 
-  read_md_file = input_file;
-  read_md_filename = pathname;
-  handle_file (handle_directive);
+  m_read_md_file = input_file;
+  m_read_md_filename = pathname;
+
+  handle_file ();
 
   /* Restore the old cursor.  */
-  read_md_file = old_file;
-  read_md_filename = old_filename;
-  read_md_lineno = old_lineno;
+  m_read_md_file = old_file;
+  m_read_md_filename = old_filename;
+  m_read_md_lineno = old_lineno;
 
   /* Do not free the pathname.  It is attached to the various rtx
      queue elements.  */
@@ -981,16 +1004,16 @@ handle_include (file_location loc, directive_handler_t handle_directive)
    read_md_filename are valid.  Use HANDLE_DIRECTIVE to handle
    unknown directives.  */
 
-static void
-handle_file (directive_handler_t handle_directive)
+void
+rtx_reader::handle_file ()
 {
   struct md_name directive;
   int c;
 
-  read_md_lineno = 1;
+  m_read_md_lineno = 1;
   while ((c = read_skip_spaces ()) != EOF)
     {
-      file_location loc (read_md_filename, read_md_lineno);
+      file_location loc = get_current_location ();
       if (c != '(')
 	fatal_expected_char ('(', c);
 
@@ -1002,49 +1025,51 @@ handle_file (directive_handler_t handle_directive)
       else if (strcmp (directive.string, "define_c_enum") == 0)
 	handle_enum (loc, false);
       else if (strcmp (directive.string, "include") == 0)
-	handle_include (loc, handle_directive);
-      else if (handle_directive)
-	handle_directive (loc, directive.string);
+	handle_include (loc);
       else
-	read_skip_construct (1, loc);
+	handle_unknown_directive (loc, directive.string);
 
       require_char_ws (')');
     }
-  fclose (read_md_file);
+  fclose (m_read_md_file);
 }
 
-/* Like handle_file, but for top-level files.  Set up in_fname and
-   base_dir accordingly.  */
+/* Like handle_file, but for top-level files.  Set up m_toplevel_fname
+   and m_base_dir accordingly.  */
 
-static void
-handle_toplevel_file (directive_handler_t handle_directive)
+void
+rtx_reader::handle_toplevel_file ()
 {
   const char *base;
 
-  in_fname = read_md_filename;
-  base = lbasename (in_fname);
-  if (base == in_fname)
-    base_dir = NULL;
+  m_toplevel_fname = m_read_md_filename;
+  base = lbasename (m_toplevel_fname);
+  if (base == m_toplevel_fname)
+    m_base_dir = NULL;
   else
-    base_dir = xstrndup (in_fname, base - in_fname);
+    m_base_dir = xstrndup (m_toplevel_fname, base - m_toplevel_fname);
+
+  handle_file ();
+}
 
-  handle_file (handle_directive);
+file_location
+rtx_reader::get_current_location () const
+{
+  return file_location (m_read_md_filename, m_read_md_lineno);
 }
 
 /* Parse a -I option with argument ARG.  */
 
-static void
-parse_include (const char *arg)
+void
+rtx_reader::add_include_path (const char *arg)
 {
   struct file_name_list *dirtmp;
 
   dirtmp = XNEW (struct file_name_list);
   dirtmp->next = 0;
   dirtmp->fname = arg;
-  *last_dir_md_include_ptr = dirtmp;
-  last_dir_md_include_ptr = &dirtmp->next;
-  if (strlen (dirtmp->fname) > max_include_len)
-    max_include_len = strlen (dirtmp->fname);
+  *m_last_dir_md_include_ptr = dirtmp;
+  m_last_dir_md_include_ptr = &dirtmp->next;
 }
 
 /* The main routine for reading .md files.  Try to process all the .md
@@ -1054,16 +1079,11 @@ parse_include (const char *arg)
 
    PARSE_OPT, if nonnull, is passed all unknown command-line arguments.
    It should return true if it recognizes the argument or false if a
-   generic error should be reported.
-
-   If HANDLE_DIRECTIVE is nonnull, the parser calls it for each
-   unknown directive, otherwise it just skips such directives.
-   See the comment above the directive_handler_t definition for
-   details about the callback's interface.  */
+   generic error should be reported.  */
 
 bool
-read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
-	       directive_handler_t handle_directive)
+rtx_reader::read_md_files (int argc, const char **argv,
+			   bool (*parse_opt) (const char *))
 {
   int i;
   bool no_more_options;
@@ -1101,9 +1121,9 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 	if (argv[i][1] == 'I')
 	  {
 	    if (argv[i][2] != '\0')
-	      parse_include (argv[i] + 2);
+	      add_include_path (argv[i] + 2);
 	    else if (++i < argc)
-	      parse_include (argv[i]);
+	      add_include_path (argv[i]);
 	    else
 	      fatal ("directory name missing after -I option");
 	    continue;
@@ -1131,9 +1151,9 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 	      if (already_read_stdin)
 		fatal ("cannot read standard input twice");
 
-	      read_md_file = stdin;
-	      read_md_filename = "<stdin>";
-	      handle_toplevel_file (handle_directive);
+	      m_read_md_file = stdin;
+	      m_read_md_filename = "<stdin>";
+	      handle_toplevel_file ();
 	      already_read_stdin = true;
 	      continue;
 	    }
@@ -1149,14 +1169,14 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 
       /* If we get here we are looking at a non-option argument, i.e.
 	 a file to be processed.  */
-      read_md_filename = argv[i];
-      read_md_file = fopen (read_md_filename, "r");
-      if (read_md_file == 0)
+      m_read_md_filename = argv[i];
+      m_read_md_file = fopen (m_read_md_filename, "r");
+      if (m_read_md_file == 0)
 	{
-	  perror (read_md_filename);
+	  perror (m_read_md_filename);
 	  return false;
 	}
-      handle_toplevel_file (handle_directive);
+      handle_toplevel_file ();
       num_files++;
     }
 
@@ -1164,10 +1184,19 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
      read the standard input now.  */
   if (num_files == 0 && !already_read_stdin)
     {
-      read_md_file = stdin;
-      read_md_filename = "<stdin>";
-      handle_toplevel_file (handle_directive);
+      m_read_md_file = stdin;
+      m_read_md_filename = "<stdin>";
+      handle_toplevel_file ();
     }
 
   return !have_error;
 }
+
+/* class noop_reader : public rtx_reader */
+
+/* A dummy implementation which skips unknown directives.  */
+void
+noop_reader::handle_unknown_directive (file_location loc, const char *)
+{
+  read_skip_construct (1, loc);
+}
diff --git a/gcc/read-md.h b/gcc/read-md.h
index fa25951..82a628b 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -90,16 +90,81 @@ struct enum_type {
   unsigned int num_values;
 };
 
-/* A callback that handles a single .md-file directive, up to but not
-   including the closing ')'.  It takes two arguments: the file position
-   at which the directive started, and the name of the directive.  The next
-   unread character is the optional space after the directive name.  */
-typedef void (*directive_handler_t) (file_location, const char *);
-
-extern const char *in_fname;
-extern FILE *read_md_file;
-extern int read_md_lineno;
-extern const char *read_md_filename;
+class rtx_reader
+{
+ public:
+  rtx_reader ();
+  virtual ~rtx_reader ();
+
+  bool read_md_files (int, const char **, bool (*) (const char *));
+
+  /* A hook that handles a single .md-file directive, up to but not
+     including the closing ')'.  It takes two arguments: the file position
+     at which the directive started, and the name of the directive.  The next
+     unread character is the optional space after the directive name.  */
+  virtual void handle_unknown_directive (file_location, const char *) = 0;
+
+  file_location get_current_location () const;
+
+  int read_char (void);
+  void unread_char (int ch);
+
+  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; }
+
+ private:
+  /* A singly-linked list of filenames.  */
+  struct file_name_list {
+    struct file_name_list *next;
+    const char *fname;
+  };
+
+ private:
+  void handle_file ();
+  void handle_toplevel_file ();
+  void handle_include (file_location loc);
+  void add_include_path (const char *arg);
+
+ private:
+  /* The name of the toplevel file that indirectly included
+     m_read_md_file.  */
+  const char *m_toplevel_fname;
+
+  /* The directory part of m_toplevel_fname
+     NULL if m_toplevel_fname is a bare filename.  */
+  char *m_base_dir;
+
+  /* The file we are reading.  */
+  FILE *m_read_md_file;
+
+  /* The filename of m_read_md_file.  */
+  const char *m_read_md_filename;
+
+  /* The current line number in m_read_md_file.  */
+  int m_read_md_lineno;
+
+  /* The first directory to search.  */
+  file_name_list *m_first_dir_md_include;
+
+  /* A pointer to the null terminator of the md include chain.  */
+  file_name_list **m_last_dir_md_include_ptr;
+};
+
+/* Global singleton.  */
+extern rtx_reader *rtx_reader_ptr;
+
+/* An rtx_reader subclass which skips unknown directives.  */
+
+class noop_reader : public rtx_reader
+{
+ public:
+  noop_reader () : rtx_reader () {}
+
+  /* A dummy implementation which skips unknown directives.  */
+  void handle_unknown_directive (file_location, const char *);
+};
+
 extern struct obstack string_obstack;
 extern void (*include_callback) (const char *);
 
@@ -108,12 +173,7 @@ extern void (*include_callback) (const char *);
 static inline int
 read_char (void)
 {
-  int ch;
-
-  ch = getc (read_md_file);
-  if (ch == '\n')
-    read_md_lineno++;
-  return ch;
+  return rtx_reader_ptr->read_char ();
 }
 
 /* Put back CH, which was the last character read from the MD file.  */
@@ -121,9 +181,7 @@ read_char (void)
 static inline void
 unread_char (int ch)
 {
-  if (ch == '\n')
-    read_md_lineno--;
-  ungetc (ch, read_md_file);
+  rtx_reader_ptr->unread_char (ch);
 }
 
 extern hashval_t leading_string_hash (const void *);
@@ -151,7 +209,5 @@ 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 *);
-extern bool read_md_files (int, const char **, bool (*) (const char *),
-			   directive_handler_t);
 
 #endif /* GCC_READ_MD_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 4614e35..eda9382 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -1234,6 +1234,7 @@ read_rtx_code (const char *code_name)
 		  || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
 	    {
 	      char line_name[20];
+	      const char *read_md_filename = rtx_reader_ptr->get_filename ();
 	      const char *fn = (read_md_filename ? read_md_filename : "rtx");
 	      const char *slash;
 	      for (slash = fn; *slash; slash ++)
@@ -1241,7 +1242,7 @@ read_rtx_code (const char *code_name)
 		  fn = slash + 1;
 	      obstack_1grow (&string_obstack, '*');
 	      obstack_grow (&string_obstack, fn, strlen (fn));
-	      sprintf (line_name, ":%d", read_md_lineno);
+	      sprintf (line_name, ":%d", rtx_reader_ptr->get_lineno ());
 	      obstack_grow (&string_obstack, line_name, strlen (line_name)+1);
 	      stringbuf = XOBFINISH (&string_obstack, char *);
 	    }
-- 
1.8.5.3

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

* [PATCH] print-rtx.c: add 'h', v' and 'p' prefixes to regnos
  2016-09-20 19:35                   ` David Malcolm
@ 2016-09-21 18:59                     ` David Malcolm
  2016-09-28 16:30                       ` Jeff Law
  0 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-21 18:59 UTC (permalink / raw)
  To: Jeff Law, Bernd Schmidt, gcc-patches; +Cc: David Malcolm

On Tue, 2016-09-20 at 15:12 -0400, David Malcolm wrote:
> On Tue, 2016-09-20 at 09:20 -0600, Jeff Law wrote:
> > On 09/20/2016 08:34 AM, Bernd Schmidt wrote:
> > > On 09/20/2016 04:32 PM, David Malcolm wrote:
> > > >
> > > > To summarize so far: you want every pseudo to have its regno
> > > > dumped
> > > > with a 'p' prefix, and renumber them on dump (and then on
> > > > load).
> > > > OK.
> > >
> > > Renumbering is not helpful because it interferes with the view
> > > you
> > > have
> > > in the debugger. So, IMO just a prefix, and maybe
> > Yea, I guess it does since we want the numbers in the dump to be
> > the
> > same that we used to access the arrays.  So prefixing in the dump
> > with
> > adjustment of the number in the reader.
>
> To check I understand: am I right in thinking you want:
> (A) the numbers in the dump to be unmodified when dumping, so that we
> can easily look up values in arrays without confusion, and
> (B) regnums in the dump gain a 'p' prefix for values >=
>  FIRST_PSEUDO_REGISTER, so that humans and parsers can easily see
> when
> the regs are pseudos, and that
> (C) the parser will detect if a 'p'-prefixed regno actually has the
> same number as a hard reg (which can happen e.g. when a .md file
> changes, or when sharing .rtl dumps between targets), and remap the
> values on load accordingly
>
> ?
>
> (in which case we do need the regno_remapper class, or something like
> it)
>
> > >
> > > >   (reg/f:DI v1 virtual-stack-vars)
> > >
> > > this.
> > Doesn't the same apply to the number of virtual stack regs?  Those
> > are
> > in the same array as pseudos.  So ISTM we prefix in the dump, but
> > do
> > adjustment of the number in the reader?
>
> Presumably we could use "v" rather than "p" as the prefix for the
> first
> 5 pseudos (up to LAST_VIRTUAL_REGISTER), doing any adjustment at load
> time, rather than at dump time.  So the above example would look
> like:
>
>    (reg/f:DI v82 virtual-stack-vars)
>
> i.e. the 82 for x86_64's virtual-stack-vars would be prefixed with a
> 'v', and the loader would adjust it to be the current target's value
> for VIRTUAL_STACK_VARS_REGNUM.
>
> Do you like the idea of prefixing regnums of hardregs with 'h'? (so
> that all regnos get a one-char prefix) e.g.
>   (reg/i:SI h0 ax)
>   (reg/i:SF h21 xmm0)

(Replying to myself, in the hope of better demonstrating the idea)

The following patch implements this idea for RTL dumps, so that all REGNO
values in dumps get a one character prefix: 'h' for hard registers, 'v'
for virtual registers, and 'p' for non-virtual pseudos (making it easier
for both humans and parsers to grok the meaning of a REGNO).

For example, on compiling this:

  int test (int i)
  {
    return i * i;
  }

for target==x86_64, the dump for expand looks like this:

(note 1 0 4 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 v82 virtual-stack-vars)
                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
        (reg:SI h5 di [ i ])) ../../test.c:2 -1
     (nil))
(note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
(insn 6 3 7 2 (set (reg:SI p89)
        (mem/c:SI (plus:DI (reg/f:DI v82 virtual-stack-vars)
                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../test.c:3 -1
     (nil))
(insn 7 6 10 2 (parallel [
            (set (reg:SI p87 [ _2 ])
                (mult:SI (reg:SI p89)
                    (mem/c:SI (plus:DI (reg/f:DI v82 virtual-stack-vars)
                            (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])))
            (clobber (reg:CC h17 flags))
        ]) ../../test.c:3 -1
     (nil))
(insn 10 7 14 2 (set (reg:SI p88 [ <retval> ])
        (reg:SI p87 [ _2 ])) ../../test.c:3 -1
     (nil))
(insn 14 10 15 2 (set (reg/i:SI h0 ax)
        (reg:SI p88 [ <retval> ])) ../../test.c:4 -1
     (nil))
(insn 15 14 0 2 (use (reg/i:SI h0 ax)) ../../test.c:4 -1
     (nil))

Note the 'v' prefix here:
  (reg/f:DI v82 virtual-stack-vars)
the 'h' prefix here:
  (reg/i:SI h0 ax)
and the 'p' prefix here:
  (reg:SI p88 [ <retval> ])

Successfully bootstrapped on x86_64-pc-linux-gnu.
There are various regression test failures involving scan-rtl-dump
due to regexes not matching e.g.
 PASS -> FAIL : gcc.target/i386/pr20020-1.c scan-rtl-dump expand "\\(set \\(reg/i:TI 0 ax\\)"
 PASS -> FAIL : gcc.target/i386/pr20020-1.c scan-rtl-dump expand "\\(set \\(reg:TI [0-9]* \\[ <retval> \\]\\)"
If the approach is OK, I can do an updated patch that also fixes up the
relevant tests (adding the appropriate prefixes); this would touch
multiple targets.

gcc/ChangeLog:
	* print-rtl.c (print_rtx): When dumping regnos, prefix the
	number with 'h', 'v' or 'p', depending on whether it is a
	hard register, a virtual register, or a non-virtual pseudo.
	* doc/rtl.texi (Registers and Memory): Document the above change,
	adding the prefix to examples that specifically refer to hard or
	pseudo regs in the text.
---
 gcc/doc/rtl.texi | 26 +++++++++++++++++++-------
 gcc/print-rtl.c  | 18 +++++++++---------
 2 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 1b3f47e..450c041 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -1715,6 +1715,9 @@ registers and to main memory.
 @cindex hard registers
 @cindex pseudo registers
 @item (reg:@var{m} @var{n})
+@item (reg:@var{m} h@var{n})
+@item (reg:@var{m} v@var{n})
+@item (reg:@var{m} p@var{n})
 For small values of the integer @var{n} (those that are less than
 @code{FIRST_PSEUDO_REGISTER}), this stands for a reference to machine
 register number @var{n}: a @dfn{hard register}.  For larger values of
@@ -1723,6 +1726,12 @@ The compiler's strategy is to generate code assuming an unlimited
 number of such pseudo registers, and later convert them into hard
 registers or into memory references.
 
+Hard register numbers are printed in debugging dumps with a ``h''
+prefix.  Pseudo register numbers are printed with a a ``v'' or ``p''
+prefix (see the description of @code{FIRST_VIRTUAL_REGISTER} and
+@code{LAST_VIRTUAL_REGISTER} below).  The ``h'' prefix can be omitted in
+machine description files.
+
 @var{m} is the machine mode of the reference.  It is necessary because
 machines can generally refer to each register in more than one mode.
 For example, a register may contain a full word but there may be
@@ -1763,7 +1772,10 @@ Some pseudo register numbers, those within the range of
 appear during the RTL generation phase and are eliminated before the
 optimization phases.  These represent locations in the stack frame that
 cannot be determined until RTL generation for the function has been
-completed.  The following virtual register numbers are defined:
+completed.  Such numbers are printed in dumps with a 'v' prefix;
+the other non-virtual pseudo register numbers are printed with a 'p'
+prefix.
+The following virtual register numbers are defined:
 
 @table @code
 @findex VIRTUAL_INCOMING_ARGS_REGNUM
@@ -3115,14 +3127,14 @@ side-effects are computed, and second all the actual side-effects are
 performed.  For example,
 
 @smallexample
-(parallel [(set (reg:SI 1) (mem:SI (reg:SI 1)))
-           (set (mem:SI (reg:SI 1)) (reg:SI 1))])
+(parallel [(set (reg:SI h1) (mem:SI (reg:SI h1)))
+           (set (mem:SI (reg:SI h1)) (reg:SI h1))])
 @end smallexample
 
 @noindent
 says unambiguously that the values of hard register 1 and the memory
 location addressed by it are interchanged.  In both places where
-@code{(reg:SI 1)} appears as a memory address it refers to the value
+@code{(reg:SI h1)} appears as a memory address it refers to the value
 in register 1 @emph{before} the execution of the insn.
 
 It follows that it is @emph{incorrect} to use @code{parallel} and
@@ -3270,7 +3282,7 @@ reference of which this expression serves as the address.  Here is an
 example of its use:
 
 @smallexample
-(mem:DF (pre_dec:SI (reg:SI 39)))
+(mem:DF (pre_dec:SI (reg:SI p39)))
 @end smallexample
 
 @noindent
@@ -3308,8 +3320,8 @@ where @var{z} is an index register and @var{i} is a constant.
 Here is an example of its use:
 
 @smallexample
-(mem:SF (post_modify:SI (reg:SI 42) (plus (reg:SI 42)
-                                          (reg:SI 48))))
+(mem:SF (post_modify:SI (reg:SI p42) (plus (reg:SI p42)
+                                           (reg:SI p48))))
 @end smallexample
 
 This says to modify pseudo register 42 by adding the contents of pseudo
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index a905127..309dcd1 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -476,24 +476,24 @@ print_rtx (const_rtx in_rtx)
 	  unsigned int regno = REGNO (in_rtx);
 #ifndef GENERATOR_FILE
 	  if (regno < FIRST_PSEUDO_REGISTER)
-	    fprintf (outfile, " %d %s", regno, reg_names[regno]);
+	    fprintf (outfile, " h%d %s", regno, reg_names[regno]);
 	  else if (regno <= LAST_VIRTUAL_REGISTER)
 	    {
 	      if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
-		fprintf (outfile, " %d virtual-incoming-args", regno);
+		fprintf (outfile, " v%d virtual-incoming-args", regno);
 	      else if (regno == VIRTUAL_STACK_VARS_REGNUM)
-		fprintf (outfile, " %d virtual-stack-vars", regno);
+		fprintf (outfile, " v%d virtual-stack-vars", regno);
 	      else if (regno == VIRTUAL_STACK_DYNAMIC_REGNUM)
-		fprintf (outfile, " %d virtual-stack-dynamic", regno);
+		fprintf (outfile, " v%d virtual-stack-dynamic", regno);
 	      else if (regno == VIRTUAL_OUTGOING_ARGS_REGNUM)
-		fprintf (outfile, " %d virtual-outgoing-args", regno);
+		fprintf (outfile, " v%d virtual-outgoing-args", regno);
 	      else if (regno == VIRTUAL_CFA_REGNUM)
-		fprintf (outfile, " %d virtual-cfa", regno);
+		fprintf (outfile, " v%d virtual-cfa", regno);
 	      else if (regno == VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM)
-		fprintf (outfile, " %d virtual-preferred-stack-boundary",
+		fprintf (outfile, " v%d virtual-preferred-stack-boundary",
 			 regno);
 	      else
-		fprintf (outfile, " %d virtual-reg-%d", regno,
+		fprintf (outfile, " v%d virtual-reg-%d", regno,
 			 regno-FIRST_VIRTUAL_REGISTER);
 	    }
 	  else
@@ -501,7 +501,7 @@ print_rtx (const_rtx in_rtx)
 	    if (flag_dump_unnumbered && is_insn)
 	      fputc ('#', outfile);
 	    else
-	      fprintf (outfile, " %d", regno);
+	      fprintf (outfile, " p%d", regno);
 
 #ifndef GENERATOR_FILE
 	  if (REG_ATTRS (in_rtx))
-- 
1.8.5.3

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

* Re: [PATCH, v2] Introduce class rtx_reader
  2016-09-21 17:22     ` [PATCH, v2] " David Malcolm
@ 2016-09-21 20:44       ` Richard Sandiford
  0 siblings, 0 replies; 56+ messages in thread
From: Richard Sandiford @ 2016-09-21 20:44 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jeff Law, gcc-patches

David Malcolm <dmalcolm@redhat.com> writes:
> On Fri, 2016-09-16 at 16:04 -0600, Jeff Law wrote:
>> On 09/08/2016 06:30 PM, David Malcolm wrote:
>> > Bundle up various global variables within gensupport.c into a
>> > class rtx_reader, with a view towards making it easier to run the
>> > code more than once in-process.
>> > 
>> > gcc/ChangeLog:
>> > 	* genconstants.c (main): Introduce noop_reader and convert call
>> > 	to read_md_files to a method call.
>> > 	* genenums.c (main): Likewise.
>> > 	* genmddeps.c (main): Likewise.
>> > 	* genpreds.c (write_tm_constrs_h): Replace use of "in_fname"
>> > with
>> > 	rtx_reader_ptr->get_top_level_filename ().
>> > 	(write_tm_preds_h): Likewise.
>> > 	(write_insn_preds_c): Likewise.
>> > 	* gensupport.c (class gen_reader): New subclass of rtx_reader.
>> > 	(rtx_handle_directive): Convert to...
>> > 	(gen_reader::handle_unknown_directive): ...this.
>> > 	(init_rtx_reader_args_cb): Convert return type from bool to
>> > 	rtx_reader *.  Create a gen_reader instance, using it for the
>> > 	call to read_md_files.  Return it if no errors occur.
>> > 	(init_rtx_reader_args): Convert return type from bool to
>> > 	rtx_reader *.
>> > 	* gensupport.h (init_rtx_reader_args_cb): Likewise.
>> > 	(init_rtx_reader_args_cb): Likewise.
>> > 	* read-md.c (struct file_name_list): Move to class rtx_reader.
>> > 	(read_md_file): Delete in favor of rtx_reader::m_read_md_file.
>> > 	(read_md_filename): Delete in favor of
>> > 	rtx_reader::m_read_md_filename.
>> > 	(read_md_lineno): Delete in favor of
>> > rtx_reader::m_read_md_lineno.
>> > 	(in_fname): Delete in favor of rtx_reader::m_toplevel_fname.
>> > 	(base_dir): Delete in favor of rtx_reader::m_base_dir.
>> > 	(first_dir_md_include): Delete in favor of
>> > 	rtx_reader::m_first_dir_md_include.
>> > 	(last_dir_md_include_ptr): Delete in favor of
>> > 	rtx_reader::m_last_dir_md_include_ptr.
>> > 	(max_include_len): Delete.
>> > 	(rtx_reader_ptr): New.
>> > 	(fatal_with_file_and_line): Use get_filename and get_lineno
>> > 	accessors of rtx_reader_ptr.
>> > 	(require_char_ws): Likewise.
>> > 	(rtx_reader::read_char): New method, based on ::read_char.
>> > 	(rtx_reader::unread_char): New method, based on ::unread_char.
>> > 	(read_escape): Use get_filename and get_lineno accessors of
>> > 	rtx_reader_ptr.
>> > 	(read_braced_string): Use get_lineno accessor of
>> > rtx_reader_ptr.
>> > 	(read_string): Use get_filename and get_lineno accessors of
>> > 	rtx_reader_ptr.
>> > 	(rtx_reader::rtx_reader): New ctor.
>> > 	(rtx_reader::~rtx_reader): New dtor.
>> > 	(handle_include): Convert from a function to...
>> > 	(rtx_reader::handle_include): ...this method, converting
>> > 	handle_directive from a callback to a virtual function.
>> > 	(handle_file): Likewise, converting to...
>> > 	(rtx_reader::handle_file): ...this method.
>> > 	(handle_toplevel_file): Likewise, converting to...
>> > 	(rtx_reader::handle_toplevel_file): ...this method.
>> > 	(rtx_reader::get_current_location): New method.
>> > 	(parse_include): Convert from a function to...
>> > 	(rtx_reader::add_include_path): ...this method, dropping
>> > redundant
>> > 	update to unused max_include_len.
>> > 	(read_md_files): Convert from a function to...
>> > 	(rtx_reader::read_md_files): ...this method, converting
>> > 	handle_directive from a callback to a virtual function.
>> > 	(noop_reader::handle_unknown_directive): New method.
>> > 	* read-md.h (directive_handler_t): Delete this typedef.
>> > 	(in_fname): Delete.
>> > 	(read_md_file): Delete.
>> > 	(read_md_lineno): Delete.
>> > 	(read_md_filename): Delete.
>> > 	(class rtx_reader): New class.
>> > 	(rtx_reader_ptr): New decl.
>> > 	(class noop_reader): New subclass of rtx_reader.
>> > 	(read_char): Reimplement in terms of rtx_reader::read_char.
>> > 	(unread_char): Reimplement in terms of rtx_reader::unread_char.
>> > 	(read_md_files): Delete.
>> > 	* read-rtl.c (read_rtx_code): Update for deletion of globals
>> > 	read_md_filename and read_md_lineno.
>> I don't see anything terribly objectionable here.
>> 
>> It looks like you use a singleton to avoid passing the object around
>> everywhere, but given the state of all this prior to this patch, I
>> can
>> live with the cleanup as a whole.
>
> Indeed; the point of the patch is to bundle up some global state to
> better allow the reader to be run more than once in-process, so that
> the RTL frontend can have selftests; having more than one reader *alive*
> at once is out-of-scope.  Hence the use of a singleton, to minimize the
> amount of churn.
>
>> I'll note Richard Sandiford. hasn't chimed in here.  You might ping
>> him
>> directly to see if he's got any feedback.  If he doesn't prior to say
>> Wed, this is OK for the trunk.
>> 
>> jeff
>
> Thanks.
>
> Here's a slightly tweaked version, fixing a couple of missing NULL
> initializations in the rtx_reader ctor (of m_base_dir and m_read_md_file),
> which avoids a crash for the file-not-found case.
>
> Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.
>
> Richard: do you have any feedback on this?
> Otherwise, I'll assume this is still OK for trunk in a few days.

Looks really good to me, thanks.  Sorry for not picking up on it until now.

Richard

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

* [PATCH] Introduce selftest::locate_file
  2016-09-19 17:37       ` Jeff Law
@ 2016-09-22  3:23         ` David Malcolm
  2016-09-28 16:33           ` Jeff Law
  0 siblings, 1 reply; 56+ messages in thread
From: David Malcolm @ 2016-09-22  3:23 UTC (permalink / raw)
  To: Jeff Law, gcc-patches; +Cc: David Malcolm

On Mon, 2016-09-19 at 11:31 -0600, Jeff Law wrote:
> On 09/16/2016 03:19 PM, David Malcolm wrote:
> > 
> > > When possible I don't think we want the tests to be target
> > > specific.
> > > Hmm, I'm probably about to argue for Bernd's work...  The 71779
> > > testcase
> > > is a great example -- it uses high/lo_sum.  Not all targets
> > > support
> > > that
> > > -- as long as we don't try to recognize those insns we're likely
> > > OK,
> > > but
> > > that seems fragile long term.  Having an idealized target means
> > > we
> > > can
> > > ignore much of these issues.
> > 
> > An alternative would be to pick a specific target for each test.
> It's an alternative, but not one I particularly like since those
> tests
> won't be consistently run.  With an abstracted target like Bernd
> suggests we ought to be able to make most tests work with the
> abstracted
> target and minimize the number of truely target specific tests.
> 
> 
> > > So I'm real curious, what happens if you run this RTL selftest
> > > under
> > > valgrind?  I have the sneaking suspicion that we'll start doing
> > > some
> > > uninitialized memory reads.
> > 
> > I'm seeing various leaks (an htab within linemap_init for all of
> > the
> > line_table fixtures), but no uninitialized reads.
> Wow.  I must say I'm surprised.  Good news though.
> 
> 
> > >   +
> > > > +  /* 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.  */
> > > > +  const char *input_dump
> > > > +    = (";; MEM[(struct isl_obj *)&obj1] =
> > > > &isl_obj_map_vtable;\n"
> > > > +       "(insn 1045 0 1046 2 (set (reg:SI 480)\n"
> > > > +       "        (high:SI (symbol_ref:SI
> > > > (\"isl_obj_map_vtable\")
> > > > [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
> > > > y.c:12702 -1\n"
> > > > +       "     (nil))\n"
> > > > +       "(insn 1046 1045 1047 2 (set (reg/f:SI 479)\n"
> > > > +       "        (lo_sum:SI (reg:SI 480)\n"
> > > > +       "            (symbol_ref:SI (\"isl_obj_map_vtable\")
> > > > [flags
> > > > 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>))) y.c:12702
> > > > -1\n"
> > > > +       "     (expr_list:REG_EQUAL (symbol_ref:SI
> > > > (\"isl_obj_map_vtable\") [flags 0xc0] <var_decl 0x7fa0363ea240
> > > > isl_obj_map_vtable>)\n"
> > > > +       "        (nil)))\n"
> > > > +       "(insn 1047 1046 1048 2 (set (reg:DI 481)\n"
> > > > +       "        (subreg:DI (reg/f:SI 479) 0)) y.c:12702 -1\n"
> > > > +       "     (nil))\n"
> > > > +       "(insn 1048 1047 1049 2 (set (zero_extract:DI (reg/v:DI
> > > > 191
> > > > [ obj1D.17368 ])\n"
> > > > +       "            (const_int 32 [0x20])\n"
> > > > +       "            (const_int 0 [0]))\n"
> > > > +       "        (reg:DI 481)) y.c:12702 -1\n"
> > > > +       "     (nil))\n"
> > > So looking at this just makes my head hurt.  Escaping, lots of
> > > quotes,
> > > unnecessary things in the dump, etc.  The question I would have
> > > is
> > > why
> > > not have a file with the dump and read the file?
> > 
> > (nods)
> > 
> > Seems like I need to add a mechanism for telling the selftests
> > which
> > directory to load the tests relative to.
> What about putting them inside the appropriate gcc.target
> directories?
> We could have one for the "generic" target assuming we build
> something
> like that, the others could live in their target specific directory.
> 
> 
> jeff

Having selftests that read RTL dumps load them 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.  We could add target-specific directories below that dir if
necessary.

I've rewritten the rest of the patch kit to use this to load from .rtl
dump files within that directory, rather than embedding the dumps as
string literals in the C source.

The patch also exposes a selftests::path_to_src_gcc, which could be
used by a selftest to e.g. load a DejaGnu file, so that if need be
we could share .rtl input files between both -fself-test tests and
DejaGnu-based tests for the .rtl frontend.

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

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

OK for trunk once the dependencies are in?

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 332c85e..94146ae 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1876,18 +1876,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 fa1c036..603fade 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2098,9 +2098,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] 56+ messages in thread

* Re: [PATCH] print-rtx.c: add 'h', v' and 'p' prefixes to regnos
  2016-09-21 18:59                     ` [PATCH] print-rtx.c: add 'h', v' and 'p' prefixes to regnos David Malcolm
@ 2016-09-28 16:30                       ` Jeff Law
  2016-09-28 16:33                         ` Bernd Schmidt
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-28 16:30 UTC (permalink / raw)
  To: David Malcolm, Bernd Schmidt, gcc-patches

On 09/21/2016 01:01 PM, David Malcolm wrote:
>>
>> Presumably we could use "v" rather than "p" as the prefix for the
>> first
>> 5 pseudos (up to LAST_VIRTUAL_REGISTER), doing any adjustment at load
>> time, rather than at dump time.  So the above example would look
>> like:
>>
>>    (reg/f:DI v82 virtual-stack-vars)
>>
>> i.e. the 82 for x86_64's virtual-stack-vars would be prefixed with a
>> 'v', and the loader would adjust it to be the current target's value
>> for VIRTUAL_STACK_VARS_REGNUM.
>>
>> Do you like the idea of prefixing regnums of hardregs with 'h'? (so
>> that all regnos get a one-char prefix) e.g.
>>   (reg/i:SI h0 ax)
>>   (reg/i:SF h21 xmm0)
>
> (Replying to myself, in the hope of better demonstrating the idea)
>
> The following patch implements this idea for RTL dumps, so that all REGNO
> values in dumps get a one character prefix: 'h' for hard registers, 'v'
> for virtual registers, and 'p' for non-virtual pseudos (making it easier
> for both humans and parsers to grok the meaning of a REGNO).
I think you nailed it.  h, v & p prefixing for each of the register 
types, but leaving the actual register number as-is in the dump file.


> Successfully bootstrapped on x86_64-pc-linux-gnu.
> There are various regression test failures involving scan-rtl-dump
> due to regexes not matching e.g.
>  PASS -> FAIL : gcc.target/i386/pr20020-1.c scan-rtl-dump expand "\\(set \\(reg/i:TI 0 ax\\)"
>  PASS -> FAIL : gcc.target/i386/pr20020-1.c scan-rtl-dump expand "\\(set \\(reg:TI [0-9]* \\[ <retval> \\]\\)"
> If the approach is OK, I can do an updated patch that also fixes up the
> relevant tests (adding the appropriate prefixes); this would touch
> multiple targets.
Yea.  This obviously highlights some of the long term issues with making 
changes into the dump format.  As I said in our meeting yesterday, I do 
understand the desire to nail down the format :-)  But I also want to 
use the opportunity we have to make the dumps easier for your work to 
read & interpret.

jeff

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

* Re: [PATCH] print-rtx.c: add 'h', v' and 'p' prefixes to regnos
  2016-09-28 16:30                       ` Jeff Law
@ 2016-09-28 16:33                         ` Bernd Schmidt
  2016-09-28 17:11                           ` Jeff Law
  0 siblings, 1 reply; 56+ messages in thread
From: Bernd Schmidt @ 2016-09-28 16:33 UTC (permalink / raw)
  To: Jeff Law, David Malcolm, gcc-patches

On 09/28/2016 06:23 PM, Jeff Law wrote:

>>>   (reg/i:SI h0 ax)
>>>   (reg/i:SF h21 xmm0)
>>
>> (Replying to myself, in the hope of better demonstrating the idea)
>>
>> The following patch implements this idea for RTL dumps, so that all REGNO
>> values in dumps get a one character prefix: 'h' for hard registers, 'v'
>> for virtual registers, and 'p' for non-virtual pseudos (making it easier
>> for both humans and parsers to grok the meaning of a REGNO).
> I think you nailed it.  h, v & p prefixing for each of the register
> types, but leaving the actual register number as-is in the dump file.
>
I'm actually no longer quite so sure this buys us much: a port might 
have an actual register named "h0", leading to confusion. Virtual and 
hard registers also already have their real name printed after the number.

A "p" prefix for pseudos might still be a good idea, but there's still 
the issue of a real "p0" register name causing confusion.


Bernd

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

* Re: [PATCH] Introduce selftest::locate_file
  2016-09-22  3:23         ` [PATCH] Introduce selftest::locate_file David Malcolm
@ 2016-09-28 16:33           ` Jeff Law
  0 siblings, 0 replies; 56+ messages in thread
From: Jeff Law @ 2016-09-28 16:33 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 09/21/2016 06:59 PM, David Malcolm wrote:
> On Mon, 2016-09-19 at 11:31 -0600, Jeff Law wrote:
>> On 09/16/2016 03:19 PM, David Malcolm wrote:
>>>
>>>> When possible I don't think we want the tests to be target
>>>> specific.
>>>> Hmm, I'm probably about to argue for Bernd's work...  The 71779
>>>> testcase
>>>> is a great example -- it uses high/lo_sum.  Not all targets
>>>> support
>>>> that
>>>> -- as long as we don't try to recognize those insns we're likely
>>>> OK,
>>>> but
>>>> that seems fragile long term.  Having an idealized target means
>>>> we
>>>> can
>>>> ignore much of these issues.
>>>
>>> An alternative would be to pick a specific target for each test.
>> It's an alternative, but not one I particularly like since those
>> tests
>> won't be consistently run.  With an abstracted target like Bernd
>> suggests we ought to be able to make most tests work with the
>> abstracted
>> target and minimize the number of truely target specific tests.
>>
>>
>>>> So I'm real curious, what happens if you run this RTL selftest
>>>> under
>>>> valgrind?  I have the sneaking suspicion that we'll start doing
>>>> some
>>>> uninitialized memory reads.
>>>
>>> I'm seeing various leaks (an htab within linemap_init for all of
>>> the
>>> line_table fixtures), but no uninitialized reads.
>> Wow.  I must say I'm surprised.  Good news though.
>>
>>
>>>>   +
>>>>> +  /* 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.  */
>>>>> +  const char *input_dump
>>>>> +    = (";; MEM[(struct isl_obj *)&obj1] =
>>>>> &isl_obj_map_vtable;\n"
>>>>> +       "(insn 1045 0 1046 2 (set (reg:SI 480)\n"
>>>>> +       "        (high:SI (symbol_ref:SI
>>>>> (\"isl_obj_map_vtable\")
>>>>> [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
>>>>> y.c:12702 -1\n"
>>>>> +       "     (nil))\n"
>>>>> +       "(insn 1046 1045 1047 2 (set (reg/f:SI 479)\n"
>>>>> +       "        (lo_sum:SI (reg:SI 480)\n"
>>>>> +       "            (symbol_ref:SI (\"isl_obj_map_vtable\")
>>>>> [flags
>>>>> 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>))) y.c:12702
>>>>> -1\n"
>>>>> +       "     (expr_list:REG_EQUAL (symbol_ref:SI
>>>>> (\"isl_obj_map_vtable\") [flags 0xc0] <var_decl 0x7fa0363ea240
>>>>> isl_obj_map_vtable>)\n"
>>>>> +       "        (nil)))\n"
>>>>> +       "(insn 1047 1046 1048 2 (set (reg:DI 481)\n"
>>>>> +       "        (subreg:DI (reg/f:SI 479) 0)) y.c:12702 -1\n"
>>>>> +       "     (nil))\n"
>>>>> +       "(insn 1048 1047 1049 2 (set (zero_extract:DI (reg/v:DI
>>>>> 191
>>>>> [ obj1D.17368 ])\n"
>>>>> +       "            (const_int 32 [0x20])\n"
>>>>> +       "            (const_int 0 [0]))\n"
>>>>> +       "        (reg:DI 481)) y.c:12702 -1\n"
>>>>> +       "     (nil))\n"
>>>> So looking at this just makes my head hurt.  Escaping, lots of
>>>> quotes,
>>>> unnecessary things in the dump, etc.  The question I would have
>>>> is
>>>> why
>>>> not have a file with the dump and read the file?
>>>
>>> (nods)
>>>
>>> Seems like I need to add a mechanism for telling the selftests
>>> which
>>> directory to load the tests relative to.
>> What about putting them inside the appropriate gcc.target
>> directories?
>> We could have one for the "generic" target assuming we build
>> something
>> like that, the others could live in their target specific directory.
>>
>>
>> jeff
>
> Having selftests that read RTL dumps load them 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.  We could add target-specific directories below that dir if
> necessary.
>
> I've rewritten the rest of the patch kit to use this to load from .rtl
> dump files within that directory, rather than embedding the dumps as
> string literals in the C source.
>
> The patch also exposes a selftests::path_to_src_gcc, which could be
> used by a selftest to e.g. load a DejaGnu file, so that if need be
> we could share .rtl input files between both -fself-test tests and
> DejaGnu-based tests for the .rtl frontend.
>
> (Depends on the approved-when-needed
>   "[PATCH 2/9] Add selftest::read_file"
>     https://gcc.gnu.org/ml/gcc-patches/2016-09/msg00476.html ).
>
> Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.
>
> OK for trunk once the dependencies are in?
>
> 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.
I do think we should go ahead and plan for a target subdirectory.  With 
that added, this should be OK once dependencies are in.


jeff

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

* Re: [PATCH] print-rtx.c: add 'h', v' and 'p' prefixes to regnos
  2016-09-28 16:33                         ` Bernd Schmidt
@ 2016-09-28 17:11                           ` Jeff Law
  2016-09-28 17:19                             ` Bernd Schmidt
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2016-09-28 17:11 UTC (permalink / raw)
  To: Bernd Schmidt, David Malcolm, gcc-patches

On 09/28/2016 10:30 AM, Bernd Schmidt wrote:
> On 09/28/2016 06:23 PM, Jeff Law wrote:
>
>>>>   (reg/i:SI h0 ax)
>>>>   (reg/i:SF h21 xmm0)
>>>
>>> (Replying to myself, in the hope of better demonstrating the idea)
>>>
>>> The following patch implements this idea for RTL dumps, so that all
>>> REGNO
>>> values in dumps get a one character prefix: 'h' for hard registers, 'v'
>>> for virtual registers, and 'p' for non-virtual pseudos (making it easier
>>> for both humans and parsers to grok the meaning of a REGNO).
>> I think you nailed it.  h, v & p prefixing for each of the register
>> types, but leaving the actual register number as-is in the dump file.
>>
> I'm actually no longer quite so sure this buys us much: a port might
> have an actual register named "h0", leading to confusion. Virtual and
> hard registers also already have their real name printed after the number.
>
> A "p" prefix for pseudos might still be a good idea, but there's still
> the issue of a real "p0" register name causing confusion.
So how do you think we should deal with distinguishing between the 
different registers that may appear in a dump file?

The case I'm worried about is the register meanings in a testsuite dump 
file changing over time if/when new hard registers are added to the port 
or we introduce new virtual registers.

FOr hard regs and virtuals we can probably map backwards using their 
names.  So given a register in a dump, if we can't reverse map it back 
to a hard reg or a virtual, then we assume its a pseudo?

jeff

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

* Re: [PATCH] print-rtx.c: add 'h', v' and 'p' prefixes to regnos
  2016-09-28 17:11                           ` Jeff Law
@ 2016-09-28 17:19                             ` Bernd Schmidt
  2016-09-29 13:00                               ` David Malcolm
  2016-09-29 17:32                               ` Jeff Law
  0 siblings, 2 replies; 56+ messages in thread
From: Bernd Schmidt @ 2016-09-28 17:19 UTC (permalink / raw)
  To: Jeff Law, David Malcolm, gcc-patches

On 09/28/2016 06:36 PM, Jeff Law wrote:
>> A "p" prefix for pseudos might still be a good idea, but there's still
>> the issue of a real "p0" register name causing confusion.
> So how do you think we should deal with distinguishing between the
> different registers that may appear in a dump file?

I think the main problem we were trying to solve is making sure we can 
make future-proof dumps. So that would argue for allowing h0, v0, p0 
syntax in the reader, but not printing them out that way by default.

Also, if we don't already, allow hard regs to be specified by name in 
the reader, and maybe even require it for virtuals.


Bernd

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

* Re: [PATCH] print-rtx.c: add 'h', v' and 'p' prefixes to regnos
  2016-09-28 17:19                             ` Bernd Schmidt
@ 2016-09-29 13:00                               ` David Malcolm
  2016-09-29 17:32                               ` Jeff Law
  1 sibling, 0 replies; 56+ messages in thread
From: David Malcolm @ 2016-09-29 13:00 UTC (permalink / raw)
  To: Bernd Schmidt, Jeff Law, gcc-patches

On Wed, 2016-09-28 at 18:49 +0200, Bernd Schmidt wrote:
> On 09/28/2016 06:36 PM, Jeff Law wrote:
> > > A "p" prefix for pseudos might still be a good idea, but there's
> > > still
> > > the issue of a real "p0" register name causing confusion.
> > So how do you think we should deal with distinguishing between the
> > different registers that may appear in a dump file?
> 
> I think the main problem we were trying to solve is making sure we
> can 
> make future-proof dumps. So that would argue for allowing h0, v0, p0 
> syntax in the reader, but not printing them out that way by default.
> 
> Also, if we don't already, allow hard regs to be specified by name in
> the reader, and maybe even require it for virtuals.

Yes: the problems I'm trying to solve here are:
(a) making dumps more resilient against changing .md files, and
(b) where possible, allowing target-independent dump fragments where
everything is a pseudo

The issue I ran into was parsing the "r" format code, for a regno,
where print_rtx can print various things after the actual number.  My
hope with the prefix patch was to give the parser more of a hint as to
the category of reg (and to perhaps make dumps easier for humans to
read).

But it looks like the "r" format code is only ever used by REG, which
means there's always a closing parenthesis at the end of the material
emitted for the "r" format code.  So given that I *think* that the
parser already has all it needs, and that the patch is redundant.

So my plan for the reader is:
- read the number emitted by "r"
- 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).

...and to drop the regno-prefixing idea from this patch.

Hopefully this sounds sane.

(I'm also working on a function-dumping patch, which will cover CFG
information and various "crtl" information and other state that can't
be reconstructed and hence ought to be in the dump).

Dave

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

* Re: [PATCH] print-rtx.c: add 'h', v' and 'p' prefixes to regnos
  2016-09-28 17:19                             ` Bernd Schmidt
  2016-09-29 13:00                               ` David Malcolm
@ 2016-09-29 17:32                               ` Jeff Law
  1 sibling, 0 replies; 56+ messages in thread
From: Jeff Law @ 2016-09-29 17:32 UTC (permalink / raw)
  To: Bernd Schmidt, David Malcolm, gcc-patches

On 09/28/2016 10:49 AM, Bernd Schmidt wrote:
> On 09/28/2016 06:36 PM, Jeff Law wrote:
>>> A "p" prefix for pseudos might still be a good idea, but there's still
>>> the issue of a real "p0" register name causing confusion.
>> So how do you think we should deal with distinguishing between the
>> different registers that may appear in a dump file?
>
> I think the main problem we were trying to solve is making sure we can
> make future-proof dumps. So that would argue for allowing h0, v0, p0
> syntax in the reader, but not printing them out that way by default.
Correct, I'm mostly concerned with future proofing.

I'm certainly OK with a flag to create dumps in a form that's easier to 
parse, but leaving things as-is by default.


>
> Also, if we don't already, allow hard regs to be specified by name in
> the reader, and maybe even require it for virtuals.
Works for me.

jeff

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

end of thread, other threads:[~2016-09-29 17:22 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-09  0:01 [PATCH 0/9] RFC: selftests based on RTL dumps David Malcolm
2016-09-09  0:01 ` [PATCH 6/9] df selftests David Malcolm
2016-09-16 20:40   ` Jeff Law
2016-09-16 21:34     ` David Malcolm
2016-09-09  0:01 ` [PATCH 9/9] cse.c selftests David Malcolm
2016-09-16 20:34   ` Jeff Law
2016-09-16 21:28     ` David Malcolm
2016-09-19 17:37       ` Jeff Law
2016-09-22  3:23         ` [PATCH] Introduce selftest::locate_file David Malcolm
2016-09-28 16:33           ` Jeff Law
2016-09-09  0:01 ` [PATCH 4/9] Expose forcibly_ggc_collect and run it after all selftests David Malcolm
2016-09-16 20:30   ` Jeff Law
2016-09-09  0:01 ` [PATCH 2/9] Add selftest::read_file David Malcolm
2016-09-16 21:19   ` Jeff Law
2016-09-09  0:01 ` [PATCH 3/9] selftest.h: add temp_override fixture David Malcolm
2016-09-14 22:24   ` Trevor Saunders
2016-09-16 20:37   ` Jeff Law
2016-09-09  0:01 ` [PATCH 7/9] combine.c selftests David Malcolm
2016-09-16 20:45   ` Jeff Law
2016-09-16 21:39     ` David Malcolm
2016-09-09  0:01 ` [PATCH 8/9] final.c selftests David Malcolm
2016-09-16 21:12   ` Jeff Law
2016-09-16 21:41     ` David Malcolm
2016-09-19 21:38       ` Jeff Law
2016-09-09  0:01 ` [PATCH 1/9] Introduce class rtx_reader David Malcolm
2016-09-16 22:15   ` Jeff Law
2016-09-21 17:22     ` [PATCH, v2] " David Malcolm
2016-09-21 20:44       ` Richard Sandiford
2016-09-09  0:13 ` [PATCH 5/9] Introduce class function_reader David Malcolm
2016-09-16 21:31   ` Jeff Law
2016-09-16 22:04     ` David Malcolm
2016-09-19 21:39       ` Jeff Law
2016-09-12 14:14 ` [PATCH 0/9] RFC: selftests based on RTL dumps Bernd Schmidt
2016-09-12 18:59   ` David Malcolm
2016-09-13 11:35     ` Bernd Schmidt
2016-09-14 10:33       ` Bernd Schmidt
2016-09-16 20:26       ` Jeff Law
2016-09-16 21:28         ` David Malcolm
2016-09-19 17:50           ` Jeff Law
2016-09-20 14:34             ` Register numbers in RTL dumps (was Re: [PATCH 0/9] RFC: selftests based on RTL dumps) David Malcolm
2016-09-20 14:38               ` Bernd Schmidt
2016-09-20 15:26                 ` Jeff Law
2016-09-20 15:38                   ` Bernd Schmidt
2016-09-20 19:35                   ` David Malcolm
2016-09-21 18:59                     ` [PATCH] print-rtx.c: add 'h', v' and 'p' prefixes to regnos David Malcolm
2016-09-28 16:30                       ` Jeff Law
2016-09-28 16:33                         ` Bernd Schmidt
2016-09-28 17:11                           ` Jeff Law
2016-09-28 17:19                             ` Bernd Schmidt
2016-09-29 13:00                               ` David Malcolm
2016-09-29 17:32                               ` Jeff Law
2016-09-13 20:39     ` [PATCH 0/9] RFC: selftests based on RTL dumps Jeff Law
2016-09-14  8:44       ` Richard Biener
2016-09-16 20:16         ` Jeff Law
2016-09-16 21:27           ` David Malcolm
2016-09-19 12:21             ` Bernd Schmidt

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).