From 4ed0da064df7df08a5a5ad5d716c9e58133f6b88 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 23 Sep 2016 17:23:08 -0400
Subject: [PATCH 12/44] FIXME: Introduce class function_reader (v3)

FIXME: move some fns into rtx_reader
FIXME: Introduce rtx_reader::read_rtx_operand
* rtx_reader::read_rtx_code: rename 'i' to 'idx' and use 'c' rathen than 'i' for result of read_skip_spaces
* rtx_reader::read_rtx_operand:
  * make locals more tightly-scoped (tmp-wide, m, str, start, end, ptr, tmpstr)
  * rename 'i' to 'idx'
FIXME: split base_rtx_reader out from rtx_reader; move maybe_read_location into rtx_reader
FIXME: add function_reader::read_rtx_operand and move various stuff to function_reader

FIXME: Introduce class function_reader (v2)

FIXME: ChangeLog needs updating

Changed in v2:
* eliminate m_tempfile from rtl_dump_test, moving dumps out into
separate files, using selftest::locate_file
* add selftest::location to rtl_dump_test
* move various "wart" parsing from read-rtl.c to read-rtl-function.c

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/emit-rtl.c                                     |   13 +
 gcc/errors.c                                       |   23 +-
 gcc/errors.h                                       |   13 +
 gcc/function-tests.c                               |    2 +-
 gcc/function.c                                     |    3 +-
 gcc/genpreds.c                                     |    6 +-
 gcc/print-rtl.c                                    |    4 +-
 gcc/read-md.c                                      |  112 +-
 gcc/read-md.h                                      |   70 +-
 gcc/read-rtl-function.c                            | 1739 ++++++++++++++++++++
 gcc/read-rtl-function.h                            |   56 +
 gcc/read-rtl.c                                     |  244 ++-
 gcc/rtl.h                                          |    4 +
 gcc/selftest-rtl.c                                 |   78 +
 gcc/selftest-rtl.h                                 |   65 +
 gcc/selftest-run-tests.c                           |    1 +
 gcc/selftest.h                                     |    1 +
 gcc/testsuite/selftests/asr_div1.rtl               |   19 +
 gcc/testsuite/selftests/const-int.rtl              |   12 +
 .../selftests/copy-hard-reg-into-frame.rtl         |    8 +
 gcc/testsuite/selftests/example-labels.rtl         |    2 +
 gcc/testsuite/selftests/insn-with-mode.rtl         |    1 +
 gcc/testsuite/selftests/jump-to-label-ref.rtl      |    6 +
 gcc/testsuite/selftests/jump-to-return.rtl         |    6 +
 gcc/testsuite/selftests/jump-to-simple-return.rtl  |    6 +
 gcc/testsuite/selftests/note-insn-deleted.rtl      |    1 +
 gcc/testsuite/selftests/note_insn_basic_block.rtl  |    1 +
 gcc/testsuite/selftests/symbol-ref.rtl             |    3 +
 gcc/tree-dfa.c                                     |    5 +
 30 files changed, 2413 insertions(+), 96 deletions(-)
 create mode 100644 gcc/read-rtl-function.c
 create mode 100644 gcc/read-rtl-function.h
 create mode 100644 gcc/selftest-rtl.c
 create mode 100644 gcc/selftest-rtl.h
 create mode 100644 gcc/testsuite/selftests/asr_div1.rtl
 create mode 100644 gcc/testsuite/selftests/const-int.rtl
 create mode 100644 gcc/testsuite/selftests/copy-hard-reg-into-frame.rtl
 create mode 100644 gcc/testsuite/selftests/example-labels.rtl
 create mode 100644 gcc/testsuite/selftests/insn-with-mode.rtl
 create mode 100644 gcc/testsuite/selftests/jump-to-label-ref.rtl
 create mode 100644 gcc/testsuite/selftests/jump-to-return.rtl
 create mode 100644 gcc/testsuite/selftests/jump-to-simple-return.rtl
 create mode 100644 gcc/testsuite/selftests/note-insn-deleted.rtl
 create mode 100644 gcc/testsuite/selftests/note_insn_basic_block.rtl
 create mode 100644 gcc/testsuite/selftests/symbol-ref.rtl

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 4b50f0b..7c8df56 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1270,6 +1270,7 @@ OBJS = \
 	dwarf2cfi.o \
 	dwarf2out.o \
 	emit-rtl.o \
+	errors.o \
 	et-forest.o \
 	except.o \
 	explow.o \
@@ -1408,6 +1409,9 @@ OBJS = \
 	print-rtl-function.o \
 	print-tree.o \
 	profile.o \
+	read-md.o \
+	read-rtl.o \
+	read-rtl-function.o \
 	real.o \
 	realmpfr.o \
 	recog.o \
@@ -1435,6 +1439,7 @@ OBJS = \
 	sel-sched-ir.o \
 	sel-sched-dump.o \
 	sel-sched.o \
+	selftest-rtl.o \
 	selftest-run-tests.o \
 	sese.o \
 	shrink-wrap.o \
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 12bdbb0..2383f95 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -6304,5 +6304,18 @@ rtl_data::init_stack_alignment ()
   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;
+}
+
 
 #include "gt-emit-rtl.h"
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 24a1ce1..4c67b52 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -1901,7 +1901,8 @@ instantiate_decls (tree fndecl)
     instantiate_decl_rtl (DECL_RTL (DECL_VALUE_EXPR (decl)));
 
   /* Now process all variables defined in the function or its subblocks.  */
-  instantiate_decls_1 (DECL_INITIAL (fndecl));
+  if (DECL_INITIAL (fndecl))
+    instantiate_decls_1 (DECL_INITIAL (fndecl));
 
   FOR_EACH_LOCAL_DECL (cfun, ix, decl)
     if (DECL_RTL_SET_P (decl))
diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index 6db1b7b..a9092da 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -1205,7 +1205,7 @@ write_tm_constrs_h (void)
   printf ("\
 /* Generated automatically by the program '%s'\n\
    from the machine description file '%s'.  */\n\n", progname,
-	  rtx_reader_ptr->get_top_level_filename ());
+	  base_rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_CONSTRS_H\n\
@@ -1405,7 +1405,7 @@ write_tm_preds_h (void)
   printf ("\
 /* Generated automatically by the program '%s'\n\
    from the machine description file '%s'.  */\n\n", progname,
-	  rtx_reader_ptr->get_top_level_filename ());
+	  base_rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_PREDS_H\n\
@@ -1555,7 +1555,7 @@ write_insn_preds_c (void)
   printf ("\
 /* Generated automatically by the program '%s'\n\
    from the machine description file '%s'.  */\n\n", progname,
-	  rtx_reader_ptr->get_top_level_filename ());
+	  base_rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #include \"config.h\"\n\
diff --git a/gcc/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 495a8a6..4e5ec16 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -56,7 +56,7 @@ void (*include_callback) (const char *);
 
 /* Global singleton.  */
 
-rtx_reader *rtx_reader_ptr;
+base_rtx_reader *base_rtx_reader_ptr;
 
 /* A table of md_constant structures, hashed by name.  Null if no
    constant expansion should occur.  */
@@ -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.  */
 
@@ -274,8 +276,8 @@ fatal_with_file_and_line (const char *msg, ...)
 
   va_start (ap, msg);
 
-  fprintf (stderr, "%s:%d: error: ", rtx_reader_ptr->get_filename (),
-	   rtx_reader_ptr->get_lineno ());
+  fprintf (stderr, "%s:%d: error: ", base_rtx_reader_ptr->get_filename (),
+	   base_rtx_reader_ptr->get_lineno ());
   vfprintf (stderr, msg, ap);
   putc ('\n', stderr);
 
@@ -295,8 +297,8 @@ fatal_with_file_and_line (const char *msg, ...)
   context[i] = '\0';
 
   fprintf (stderr, "%s:%d: note: following context is `%s'\n",
-	   rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
-	   context);
+	   base_rtx_reader_ptr->get_filename (),
+	   base_rtx_reader_ptr->get_lineno (), context);
 
   va_end (ap);
   exit (1);
@@ -345,7 +347,7 @@ read_skip_spaces (void)
 	    if (c != '*')
 	      {
 		unread_char (c);
-		fatal_with_file_and_line ("stray '/' in file");
+		return '/';
 	      }
 
 	    prevc = 0;
@@ -399,7 +401,7 @@ void require_word_ws (const char *expected)
 /* Read the next character from the file.  */
 
 int
-rtx_reader::read_char (void)
+base_rtx_reader::read_char (void)
 {
   int ch;
 
@@ -413,7 +415,7 @@ rtx_reader::read_char (void)
 /* Put back CH, which was the last character read from the file.  */
 
 void
-rtx_reader::unread_char (int ch)
+base_rtx_reader::unread_char (int ch)
 {
   if (ch == '\n')
     m_read_md_lineno--;
@@ -433,8 +435,8 @@ peek_char (void)
 /* Read an rtx code name into NAME.  It is terminated by any of the
    punctuation chars of rtx printed syntax.  */
 
-void
-read_name (struct md_name *name)
+static bool
+read_name_1 (struct md_name *name, file_location *out_loc)
 {
   int c;
   size_t i;
@@ -472,8 +474,12 @@ read_name (struct md_name *name)
       c = read_char ();
     }
 
+  unread_char (c);
+  *out_loc = base_rtx_reader_ptr->get_current_location ();
+  read_char ();
+
   if (i == 0)
-    fatal_with_file_and_line ("missing name or number");
+    return false;
 
   name->buffer[i] = 0;
   name->string = name->buffer;
@@ -494,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 = base_rtx_reader_ptr->get_current_location ();
+      read_skip_construct (0, loc);
+      /* Skip the ')'.  */
+      read_char ();
+      name->buffer[0] = 0;
+      name->string = name->buffer;
+    }
+  return loc;
 }
 
 /* Subroutine of the string readers.  Handles backslash escapes.
@@ -540,8 +576,8 @@ read_escape (void)
       /* pass anything else through, but issue a warning.  */
     default:
       fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
-	       rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
-	       c);
+	       base_rtx_reader_ptr->get_filename (),
+	       base_rtx_reader_ptr->get_lineno (), c);
       obstack_1grow (&string_obstack, '\\');
       break;
     }
@@ -584,7 +620,7 @@ read_braced_string (void)
 {
   int c;
   int brace_depth = 1;  /* caller-processed */
-  unsigned long starting_read_md_lineno = rtx_reader_ptr->get_lineno ();
+  unsigned long starting_read_md_lineno = base_rtx_reader_ptr->get_lineno ();
 
   obstack_1grow (&string_obstack, '{');
   while (brace_depth)
@@ -630,7 +666,7 @@ read_string (int star_if_braced)
       c = read_skip_spaces ();
     }
 
-  old_lineno = rtx_reader_ptr->get_lineno ();
+  old_lineno = base_rtx_reader_ptr->get_lineno ();
   if (c == '"')
     stringbuf = read_quoted_string ();
   else if (c == '{')
@@ -639,13 +675,21 @@ 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);
 
   if (saw_paren)
     require_char_ws (')');
 
-  set_md_ptr_loc (stringbuf, rtx_reader_ptr->get_filename (), old_lineno);
+  set_md_ptr_loc (stringbuf, base_rtx_reader_ptr->get_filename (), old_lineno);
   return stringbuf;
 }
 
@@ -794,8 +838,8 @@ add_constant (htab_t defs, char *name, char *value,
 /* Process a define_constants directive, starting with the optional space
    after the "define_constants".  */
 
-static void
-handle_constants (void)
+void
+base_rtx_reader::handle_constants ()
 {
   int c;
   htab_t defs;
@@ -848,8 +892,8 @@ md_decimal_string (int number)
    number on which the directive started and MD_P is true if the
    directive is a define_enum rather than a define_c_enum.  */
 
-static void
-handle_enum (file_location loc, bool md_p)
+void
+base_rtx_reader::handle_enum (file_location loc, bool md_p)
 {
   char *enum_name, *value_name;
   struct md_name name;
@@ -931,9 +975,9 @@ traverse_enum_types (htab_trav callback, void *info)
 }
 
 
-/* Constructor for rtx_reader.  */
+/* Constructor for base_rtx_reader.  */
 
-rtx_reader::rtx_reader ()
+base_rtx_reader::base_rtx_reader ()
 : m_toplevel_fname (NULL),
   m_base_dir (NULL),
   m_read_md_file (NULL),
@@ -943,12 +987,12 @@ rtx_reader::rtx_reader ()
   m_last_dir_md_include_ptr (&m_first_dir_md_include)
 {
   /* Set the global singleton pointer.  */
-  rtx_reader_ptr = this;
+  base_rtx_reader_ptr = this;
 }
 
-/* rtx_reader's destructor.  */
+/* base_rtx_reader's destructor.  */
 
-rtx_reader::~rtx_reader ()
+base_rtx_reader::~base_rtx_reader ()
 {
   free (m_base_dir);
 
@@ -972,7 +1016,7 @@ rtx_reader::~rtx_reader ()
   obstack_free (&string_obstack, NULL);
 
   /* Clear the global singleton pointer.  */
-  rtx_reader_ptr = NULL;
+  base_rtx_reader_ptr = NULL;
 }
 
 /* Process an "include" directive, starting with the optional space
@@ -981,7 +1025,7 @@ rtx_reader::~rtx_reader ()
    which the "include" occurred.  */
 
 void
-rtx_reader::handle_include (file_location loc)
+base_rtx_reader::handle_include (file_location loc)
 {
   const char *filename;
   const char *old_filename;
@@ -1057,7 +1101,7 @@ rtx_reader::handle_include (file_location loc)
    unknown directives.  */
 
 void
-rtx_reader::handle_file ()
+base_rtx_reader::handle_file ()
 {
   struct md_name directive;
   int c;
@@ -1090,7 +1134,7 @@ rtx_reader::handle_file ()
    and m_base_dir accordingly.  */
 
 void
-rtx_reader::handle_toplevel_file ()
+base_rtx_reader::handle_toplevel_file ()
 {
   const char *base;
 
@@ -1105,7 +1149,7 @@ rtx_reader::handle_toplevel_file ()
 }
 
 file_location
-rtx_reader::get_current_location () const
+base_rtx_reader::get_current_location () const
 {
   return file_location (m_read_md_filename, m_read_md_lineno);
 }
@@ -1113,7 +1157,7 @@ rtx_reader::get_current_location () const
 /* Parse a -I option with argument ARG.  */
 
 void
-rtx_reader::add_include_path (const char *arg)
+base_rtx_reader::add_include_path (const char *arg)
 {
   struct file_name_list *dirtmp;
 
@@ -1134,8 +1178,8 @@ rtx_reader::add_include_path (const char *arg)
    generic error should be reported.  */
 
 bool
-rtx_reader::read_md_files (int argc, const char **argv,
-			   bool (*parse_opt) (const char *))
+base_rtx_reader::read_md_files (int argc, const char **argv,
+				bool (*parse_opt) (const char *))
 {
   int i;
   bool no_more_options;
@@ -1244,7 +1288,7 @@ rtx_reader::read_md_files (int argc, const char **argv,
   return !have_error;
 }
 
-/* class noop_reader : public rtx_reader */
+/* class noop_reader : public base_rtx_reader */
 
 /* A dummy implementation which skips unknown directives.  */
 void
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 0410875..90c4f96 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,11 +79,17 @@ struct enum_type {
   unsigned int num_values;
 };
 
-class rtx_reader
+/* A class for reading .md files and RTL dump files.
+   Implemented in read-md.c.
+   This class handles reading top-level directives including the
+   "include" directive.  It does not handle parsing nested directives;
+   for that see rtx_reader below (in read-rtl.c).  */
+
+class base_rtx_reader
 {
  public:
-  rtx_reader ();
-  virtual ~rtx_reader ();
+  base_rtx_reader ();
+  virtual ~base_rtx_reader ();
 
   bool read_md_files (int, const char **, bool (*) (const char *));
 
@@ -104,6 +99,9 @@ class rtx_reader
      unread character is the optional space after the directive name.  */
   virtual void handle_unknown_directive (file_location, const char *) = 0;
 
+  void handle_constants ();
+  void handle_enum (file_location loc, bool md_p);
+
   file_location get_current_location () const;
 
   int read_char (void);
@@ -151,20 +149,45 @@ class rtx_reader
   file_name_list **m_last_dir_md_include_ptr;
 };
 
-/* Global singleton.  */
-extern rtx_reader *rtx_reader_ptr;
+/* Global singleton; constrast with rtx_reader_ptr below.  */
+extern base_rtx_reader *base_rtx_reader_ptr;
 
-/* An rtx_reader subclass which skips unknown directives.  */
+/* A base_rtx_reader subclass which skips unknown directives, for
+   the gen* tools that purely use read-md.o.  */
 
-class noop_reader : public rtx_reader
+class noop_reader : public base_rtx_reader
 {
  public:
-  noop_reader () : rtx_reader () {}
+  noop_reader () : base_rtx_reader () {}
 
   /* A dummy implementation which skips unknown directives.  */
   void handle_unknown_directive (file_location, const char *);
 };
 
+/* A base_rtx_reader subclass that actually handles full rtx expressions.
+   Implemented in read-rtl.c.  */
+
+class rtx_reader : public base_rtx_reader
+{
+ public:
+  rtx_reader ();
+  ~rtx_reader ();
+
+  rtx read_rtx_code (const char *);
+  virtual rtx read_rtx_operand (rtx return_rtx, int idx);
+  rtx read_nested_rtx (void);
+  rtx read_rtx_variadic (rtx);
+
+  char *read_until (const char *terminator_chars, bool consume_terminator);
+
+  virtual void handle_any_trailing_information (rtx) {}
+
+  virtual rtx postprocess (rtx x) { return x; }
+};
+
+/* Global singleton; constrast with base_rtx_reader_ptr above.  */
+extern rtx_reader *rtx_reader_ptr;
+
 extern struct obstack string_obstack;
 extern void (*include_callback) (const char *);
 
@@ -173,7 +196,7 @@ extern void (*include_callback) (const char *);
 static inline int
 read_char (void)
 {
-  return rtx_reader_ptr->read_char ();
+  return base_rtx_reader_ptr->read_char ();
 }
 
 /* Put back CH, which was the last character read from the MD file.  */
@@ -181,7 +204,7 @@ read_char (void)
 static inline void
 unread_char (int ch)
 {
-  rtx_reader_ptr->unread_char (ch);
+  base_rtx_reader_ptr->unread_char (ch);
 }
 
 extern int peek_char (void);
@@ -204,7 +227,8 @@ extern int read_skip_spaces (void);
 extern void require_char (char expected);
 extern void require_char_ws (char expected);
 extern void require_word_ws (const char *expected);
-extern void read_name (struct md_name *);
+extern file_location read_name (struct md_name *);
+extern file_location read_name_or_nil (struct md_name *);
 extern char *read_quoted_string (void);
 extern char *read_string (int);
 extern int n_comma_elts (const char *);
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
new file mode 100644
index 0000000..a9b9578
--- /dev/null
+++ b/gcc/read-rtl-function.c
@@ -0,0 +1,1739 @@
+/* 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 (function_reader_policy *policy);
+  ~function_reader ();
+
+  rtx read_rtx_operand (rtx return_rtx, int idx) FINAL OVERRIDE;
+
+  void handle_any_trailing_information (rtx return_rtx) FINAL OVERRIDE;
+
+  void handle_unknown_directive (file_location, const char *) FINAL OVERRIDE;
+
+  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);
+
+  rtx postprocess (rtx);
+
+  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:
+  int remap_regno (int dumped_regno) const;
+  rtx consolidate_singletons (rtx x);
+  void maybe_read_location (int operand_idx, rtx insn);
+  void create_cfg_and_basic_blocks ();
+
+ private:
+  function_reader_policy *m_policy;
+  struct uid_hash : int_hash <int, -1, -2> {};
+  hash_map<uid_hash, rtx_insn *> m_insns_by_uid;
+  auto_vec<fixup *> m_fixups;
+  bitmap_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 (function_reader_policy *policy)
+: rtx_reader (),
+  m_policy (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;
+}
+
+/* FIXME.  */
+
+static void
+strip_trailing_whitespace (char *desc)
+{
+  char *terminator = desc + strlen (desc);
+  while (desc < terminator)
+    {
+      terminator--;
+      if (ISSPACE (*terminator))
+	*terminator = '\0';
+      else
+	break;
+    }
+}
+
+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);
+}
+
+/* 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
+function_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);
+}
+
+/* FIXME.  */
+
+rtx
+function_reader::read_rtx_operand (rtx return_rtx, int idx)
+{
+  RTX_CODE code = GET_CODE (return_rtx);
+  const char *format_ptr = GET_RTX_FORMAT (code);
+  struct md_name name;
+
+  /* Override the regular parser for some format codes.  */
+  switch (format_ptr[idx])
+    {
+    case 'u':
+      {
+	/* 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)
+	  add_fixup_insn_uid (loc, return_rtx, idx, insn_id);
+	/* Don't run regular parser for 'u'.  */
+	return return_rtx;
+      }
+      break;
+
+    case 'i':
+    case 'n':
+      {
+	/* Handle some of the extra information that print_rtx
+	   can write out for these cases.  */
+	/* print_rtx only writes out operand 5 for notes
+	   for NOTE_KIND values NOTE_INSN_DELETED_LABEL
+	   and NOTE_INSN_DELETED_DEBUG_LABEL.  */
+	if (idx == 5 && NOTE_P (return_rtx))
+	  return return_rtx;
+
+	if (idx == 4 && INSN_P (return_rtx))
+	  {
+	    maybe_read_location (idx, return_rtx);
+	    return return_rtx;
+	  }
+
+	read_name (&name);
+	int value;
+	if (format_ptr[idx] == 'n')
+	  value = parse_note_insn_name (name.string);
+	else
+	  value = atoi (name.string);
+	XINT (return_rtx, idx) = value;
+
+	/* print-rtl.c prints the names of recognized insns, after
+	   the insn code, wrapping them in braces.  Skip them,
+	   and reset the insn code to be unrecognized, since insn
+	   codes are likely to change every time the .md files
+	   change.  */
+	if (idx == 5 && INSN_P (return_rtx) && format_ptr[idx] == '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;
+		}
+	    }
+
+	/* Don't run regular parser.  */
+	return return_rtx;
+      }
+      break;
+
+    case 'B':
+      {
+	file_location loc = read_name_or_nil (&name);
+	int bb_idx = atoi (name.string);
+	if (bb_idx)
+	  add_fixup_bb (loc, return_rtx, idx, bb_idx);
+	/* Don't run regular parser.  */
+	return return_rtx;
+      }
+      break;
+
+    default:
+      break;
+    }
+
+  /* Call base class implementation.  */
+  return_rtx = rtx_reader::read_rtx_operand (return_rtx, idx);
+
+  /* Handle any additional parsing needed to handle what the dump
+     could contain.  */
+  switch (format_ptr[idx])
+    {
+    case '0':
+      {
+	int c;
+	if (idx == 1 && code == SYMBOL_REF)
+	  {
+	    /* Possibly wrote " [flags %#x]", SYMBOL_REF_FLAGS (in_rtx).  */
+	    c = read_skip_spaces ();
+	    if (c == '[')
+	      {
+		file_location loc = read_name (&name);
+		if (strcmp (name.string, "flags"))
+		  error_at (loc, "was expecting `%s'", "flags");
+		read_name (&name);
+		SYMBOL_REF_FLAGS (return_rtx) = strtol (name.string, NULL, 16);
+
+		/* We can't reconstruct SYMBOL_REF_BLOCK; set it to NULL.  */
+		if (SYMBOL_REF_HAS_BLOCK_INFO_P (return_rtx))
+		  SYMBOL_REF_BLOCK (return_rtx) = NULL;
+
+		require_char (']');
+	      }
+	    else
+	      unread_char (c);
+
+	    /* Possibly wrote:
+		print_node_brief (outfile, "", SYMBOL_REF_DECL (in_rtx),
+				  dump_flags);  */
+	    c = read_skip_spaces ();
+	    if (c == '<')
+	      {
+		/* Skip the content for now.  */
+		while (1)
+		  {
+		    char ch = read_char ();
+		    if (ch == '>')
+		      break;
+		  }
+	      }
+	    else
+	      unread_char (c);
+	  }
+	else if (idx == 3 && code == NOTE)
+	  {
+	    /* Note-specific data appears for operand 3, which annoyingly
+	       is before the enum specifying which kind of note we have
+	       (operand 4).  */
+	    c = read_skip_spaces ();
+	    if (c == '[')
+	      {
+		/* Possibly data for a NOTE_INSN_BASIC_BLOCK, of the form:
+		   [bb %d].  */
+		file_location bb_loc = read_name (&name);
+		if (strcmp (name.string, "bb"))
+		  error_at (bb_loc, "was expecting `%s'", "bb");
+		read_name (&name);
+		int bb_idx = atoi (name.string);
+		add_fixup_note_insn_basic_block (bb_loc, return_rtx, idx,
+						 bb_idx);
+		require_char_ws (']');
+	    }
+	  else
+	    unread_char (c);
+	}
+      else if (idx == 7 && JUMP_P (return_rtx))
+	{
+	  c = read_skip_spaces ();
+	  if (c != '-')
+	    {
+	      unread_char (c);
+	      break;
+	    }
+	  require_char ('>');
+	  file_location loc = read_name (&name);
+	  add_fixup_jump_label (loc, return_rtx, idx, name.string);
+	}
+      }
+      break;
+
+    case 'w':
+      {
+	/* Strip away the redundant hex dump of the value.  */
+	require_char_ws ('[');
+	read_name (&name);
+	require_char_ws (']');
+      }
+      break;
+
+    case 'r':
+      {
+	unsigned int dumped_regno = REGNO (return_rtx);
+
+	/* Potentially remap the regno to take into account differences
+	   between the dump and this target.  */
+	int effective_regno = remap_regno (dumped_regno);
+	set_regno_raw (return_rtx, effective_regno, 1);
+
+	/* Consolidate singletons.  */
+	return_rtx = consolidate_singletons (return_rtx);
+
+	ORIGINAL_REGNO (return_rtx) = effective_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 = get_current_location ();
+	    char *desc = read_until ("]", true);
+	    strip_trailing_whitespace (desc);
+	    const char *desc_start = desc;
+	    /* If ORIGINAL_REGNO (rtx) != regno, we will have:
+	       "orig:%i", ORIGINAL_REGNO (rtx).
+	       Consume it, we don't set ORIGINAL_REGNO, since we can
+	       get that from the 2nd copy later.  */
+	    if (0 == strncmp (desc, "orig:", 5))
+	      {
+		expect_original_regno = true;
+		desc_start += 5;
+		/* Skip to any whitespace following the integer.  */
+		  const char *space = strchr (desc_start, ' ');
+		  if (space)
+		    desc_start = space + 1;
+		}
+	      /* Any remaining text may be the REG_EXPR.  Alternatively we have
+		 no REG_ATTRS, and instead we have ORIGINAL_REGNO.  */
+	      if (ISDIGIT (*desc_start))
+		{
+		  /* Assume we have ORIGINAL_REGNO.  */
+		  ORIGINAL_REGNO (return_rtx) = atoi (desc_start);
+		}
+	      else
+		{
+		  /* Assume we have REG_EXPR.  */
+		  add_fixup_expr (loc, return_rtx, desc_start);
+		}
+	      free (desc);
+	    }
+	  else
+	    unread_char (ch);
+	  if (expect_original_regno)
+	    {
+	      require_char_ws ('[');
+	      char *desc = read_until ("]", true);
+	      ORIGINAL_REGNO (return_rtx) = atoi (desc);
+	      free (desc);
+	    }
+      }
+      break;
+
+    default:
+      break;
+    }
+
+  return return_rtx;
+}
+
+/* Implementation of rtx_reader::handle_any_trailing_information.
+   Handle the various additional information that print-rtl.c can
+   write after the regular fields.  */
+
+void
+function_reader::handle_any_trailing_information (rtx return_rtx)
+{
+  struct md_name name;
+
+  switch (GET_CODE (return_rtx))
+    {
+      case MEM:
+	{
+	  int ch;
+	  require_char_ws ('[');
+	  read_name (&name);
+	  MEM_ALIAS_SET (return_rtx) = atoi (name.string);
+	  /* We have either a MEM_EXPR, or a space.  */
+	  if (peek_char () != ' ')
+	    {
+	      file_location loc = get_current_location ();
+	      char *desc = read_until (" +", false);
+	      add_fixup_expr (loc, consolidate_singletons (return_rtx), desc);
+	      free (desc);
+	    }
+	  else
+	    read_char ();
+
+	  /* We may optionally have '+' for MEM_OFFSET_KNOWN_P.  */
+	  ch = read_skip_spaces ();
+	  if (ch == '+')
+	    {
+	      read_name (&name);
+	      MEM_OFFSET_KNOWN_P (return_rtx) = 1;
+	      MEM_OFFSET (return_rtx) = atoi (name.string);
+	    }
+	  else
+	    unread_char (ch);
+
+	  /* Handle optional " S" for MEM_SIZE.  */
+	  ch = read_skip_spaces ();
+	  if (ch == 'S')
+	    {
+	      read_name (&name);
+	      MEM_SIZE (return_rtx) = atoi (name.string);
+	    }
+	  else
+	    unread_char (ch);
+
+	  /* Handle optional " A" for MEM_ALIGN.  */
+	  ch = read_skip_spaces ();
+	  if (ch == 'A' && peek_char () != 'S')
+	    {
+	      read_name (&name);
+	      MEM_ALIGN (return_rtx) = atoi (name.string);
+	    }
+
+	  /* Handle optional " AS" for MEM_ADDR_SPACE.  */
+	  ch = read_skip_spaces ();
+	  if (ch == 'A' && peek_char () == 'S')
+	    {
+	      read_char ();
+	      read_name (&name);
+	      MEM_ADDR_SPACE (return_rtx) = atoi (name.string);
+	    }
+	  else
+	    unread_char (ch);
+
+	  require_char (']');
+	}
+	break;
+
+      case CODE_LABEL:
+	{
+	  /* Parse LABEL_NUSES.  */
+	  require_char_ws ('[');
+	  read_name (&name);
+	  LABEL_NUSES (return_rtx) = atoi (name.string);
+	  require_word_ws ("uses");
+	  require_char_ws (']');
+	  /* TODO: parse LABEL_KIND.  */
+	  /* For now, skip until closing ')'.  */
+	  do
+	    {
+	      char ch = read_char ();
+	      if (ch == ')')
+		{
+		  unread_char (ch);
+		  break;
+		}
+	    }
+	  while (1);
+	}
+	break;
+
+      default:
+	break;
+    }
+}
+
+/* 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);
+}
+
+/* Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+				     int insn_uid)
+{
+  m_fixups.safe_push (new fixup_insn_uid (loc, insn, operand_idx, insn_uid));
+}
+
+/* Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_bb (file_location loc, rtx insn, int operand_idx,
+			       int bb_idx)
+{
+  bitmap_set_bit (&m_bb_indices, bb_idx);
+  m_fixups.safe_push (new fixup_bb (loc, insn, operand_idx, bb_idx));
+}
+
+/* Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+						  int operand_idx, int bb_idx)
+{
+  m_fixups.safe_push (new fixup_note_insn_basic_block (loc, insn, operand_idx,
+						       bb_idx));
+}
+
+/* Record the information for later post-processing.  */
+void
+function_reader::add_fixup_source_location (file_location, rtx,
+					    int, const char *, int)
+{
+  /* Empty for now.  */
+}
+
+/* Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_jump_label (file_location loc, rtx insn,
+				       int operand_idx,
+				       const char *label)
+{
+  m_fixups.safe_push (new fixup_jump_label (loc, insn, operand_idx, label));
+}
+
+/* Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_expr (file_location loc, rtx insn,
+				 const char *desc)
+{
+  gcc_assert (desc);
+  /* Fail early if the RTL reader erroneously hands us an int.  */
+  gcc_assert (!ISDIGIT (desc[0]));
+
+  m_fixups.safe_push (new fixup_expr (loc, insn, desc));
+}
+
+/* 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.  */
+
+rtx
+function_reader::consolidate_singletons (rtx x)
+{
+  if (!x)
+    return x;
+
+ switch (GET_CODE (x))
+    {
+    /* FIXME: do we need to check for VOIDmode for these?  */
+    case PC: return pc_rtx;
+    case RETURN: return ret_rtx;
+    case SIMPLE_RETURN: return simple_return_rtx;
+    case CC0: return cc0_rtx;
+
+    case REG:
+      return consolidate_reg (x);
+
+    case CONST_INT:
+      return gen_rtx_CONST_INT (GET_MODE (x), INTVAL (x));
+
+    default:
+      break;
+    }
+
+  return x;
+}
+
+/* FIXME.  */
+
+rtx
+function_reader::postprocess (rtx x)
+{
+  return consolidate_singletons (x);
+}
+
+/* Handle the optional location information written by print_rtx for
+   instructions.  Specifically, operand 4 of instructions (of type "i')
+   is printed thus:
+
+     if (INSN_HAS_LOCATION (in_insn))
+       {
+	 expanded_location xloc = insn_location (in_insn);
+	 fprintf (outfile, " %s:%i", xloc.file, xloc.line);
+       }
+
+    Hence we need to speculatively read a location of the form
+    " %s:%i", and unread the content if there wasn't one.
+
+    Assume that filenames can't contain whitespace, and can't
+    contain ':'.  */
+
+void
+function_reader::maybe_read_location (int operand_idx, rtx insn)
+{
+  file_location loc = get_current_location ();
+
+  /* Skip to first non-whitespace.  */
+  int ch = read_skip_spaces ();
+  auto_vec<char> buf;
+  buf.safe_push (ch);
+  while (1)
+    {
+      int ch = read_char ();
+      /* If we see a ':', assume we have a filename.  */
+      if (ch == ':')
+	{
+	  buf.safe_push ('\0');
+	  break;
+	}
+      buf.safe_push (ch);
+
+      /* If we see a space before ':', assume we don't have a
+	 filename.  */
+      if (ISSPACE (ch))
+	{
+	  while (!buf.is_empty ())
+	    unread_char (buf.pop ());
+	  return;
+	}
+    }
+  char *filename = buf.address ();
+  struct md_name name;
+  read_name (&name);
+
+  add_fixup_source_location (loc, insn, operand_idx,
+			     filename, atoi(name.string));
+}
+
+/* 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 *),
+			function_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 ()
+{
+  // TODO: filter on target?
+  const int dumped_first_pseudo_regno = 76;
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("asr_div1.rtl"),
+		   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 ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION,
+		   locate_file ("copy-hard-reg-into-frame.rtl"));
+
+  rtx_insn *insn = get_insn_by_uid (2);
+
+  /* The block structure and indentation here is purely for
+     readability; it mirrors the structure of the rtx.  */
+  tree mem_expr;
+  {
+    rtx pat = PATTERN (insn);
+    ASSERT_EQ (SET, GET_CODE (pat));
+    {
+      rtx dest = SET_DEST (pat);
+      ASSERT_EQ (MEM, GET_CODE (dest));
+      /* Verify the "/c" was parsed.  */
+      ASSERT_TRUE (RTX_FLAG (dest, call));
+      ASSERT_EQ (SImode, GET_MODE (dest));
+      {
+	rtx addr = XEXP (dest, 0);
+	ASSERT_EQ (PLUS, GET_CODE (addr));
+	ASSERT_EQ (DImode, GET_MODE (addr));
+	{
+	  rtx lhs = XEXP (addr, 0);
+	  ASSERT_EQ (REG, GET_CODE (lhs));
+	  /* Verify the "/f" was parsed.  */
+	  ASSERT_TRUE (RTX_FLAG (lhs, frame_related));
+	  ASSERT_EQ (DImode, GET_MODE (lhs));
+	}
+	{
+	  rtx rhs = XEXP (addr, 1);
+	  ASSERT_EQ (CONST_INT, GET_CODE (rhs));
+	  ASSERT_EQ (-4, INTVAL (rhs));
+	}
+      }
+      /* Verify the "[1 i+0 S4 A32]" was parsed.  */
+      ASSERT_EQ (1, MEM_ALIAS_SET (dest));
+      /* "i" should have been handled by synthesizing a global int
+	 variable named "i".  */
+      mem_expr = MEM_EXPR (dest);
+      ASSERT_NE (mem_expr, NULL);
+      ASSERT_EQ (VAR_DECL, TREE_CODE (mem_expr));
+      ASSERT_EQ (integer_type_node, TREE_TYPE (mem_expr));
+      ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (DECL_NAME (mem_expr)));
+      ASSERT_STREQ ("i", IDENTIFIER_POINTER (DECL_NAME (mem_expr)));
+      /* "+0".  */
+      ASSERT_TRUE (MEM_OFFSET_KNOWN_P (dest));
+      ASSERT_EQ (0, MEM_OFFSET (dest));
+      /* "S4".  */
+      ASSERT_EQ (4, MEM_SIZE (dest));
+      /* "A32.  */
+      ASSERT_EQ (32, MEM_ALIGN (dest));
+    }
+    {
+      rtx src = SET_SRC (pat);
+      ASSERT_EQ (REG, GET_CODE (src));
+      ASSERT_EQ (SImode, GET_MODE (src));
+      ASSERT_EQ (5, REGNO (src));
+      tree reg_expr = REG_EXPR (src);
+      /* "i" here should point to the same var as for the MEM_EXPR.  */
+      ASSERT_EQ (reg_expr, mem_expr);
+    }
+  }
+}
+
+/* Verify that CODE_LABEL insns are loaded correctly.  */
+
+static void
+test_loading_labels ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("example-labels.rtl"));
+
+  rtx_insn *insn_1 = get_insn_by_uid (1);
+  ASSERT_EQ (CODE_LABEL, GET_CODE (insn_1));
+  ASSERT_EQ (NULL, LABEL_NAME (insn_1));
+  ASSERT_EQ (0, LABEL_NUSES (insn_1));
+
+  rtx_insn *insn_2 = get_insn_by_uid (2);
+  ASSERT_EQ (CODE_LABEL, GET_CODE (insn_2));
+  ASSERT_STREQ ("some_label_name", LABEL_NAME (insn_2));
+  ASSERT_EQ (57, LABEL_NUSES (insn_2));
+
+  /* Ensure that label names read from a dump are GC-managed
+     and are found through the insn.  */
+  forcibly_ggc_collect ();
+  ASSERT_TRUE (ggc_marked_p (insn_2));
+  ASSERT_TRUE (ggc_marked_p (LABEL_NAME (insn_2)));
+}
+
+/* Verify that the loader copes with an insn with a mode.  */
+
+static void
+test_loading_insn_with_mode ()
+{
+  const int dumped_first_pseudo_regno = 100;
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("insn-with-mode.rtl"),
+		   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 ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("jump-to-label-ref.rtl"));
+
+  rtx_insn *jump_insn = get_insn_by_uid (1);
+  ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+
+  rtx_insn *barrier = get_insn_by_uid (2);
+  ASSERT_EQ (BARRIER, GET_CODE (barrier));
+
+  rtx_insn *code_label = get_insn_by_uid (3);
+  ASSERT_EQ (CODE_LABEL, GET_CODE (code_label));
+
+  /* Verify the jump_insn. */
+  ASSERT_EQ (4, BLOCK_FOR_INSN (jump_insn)->index);
+  ASSERT_EQ (SET, GET_CODE (PATTERN (jump_insn)));
+  /* Ensure that the "(pc)" is using the global singleton.  */
+  ASSERT_EQ (pc_rtx, SET_DEST (PATTERN (jump_insn)));
+  // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+  rtx label_ref = SET_SRC (PATTERN (jump_insn));
+  ASSERT_EQ (LABEL_REF, GET_CODE (label_ref));
+  ASSERT_EQ (code_label, LABEL_REF_LABEL (label_ref));
+  ASSERT_EQ (code_label, JUMP_LABEL (jump_insn));
+
+  /* Verify the code_label. */
+  ASSERT_EQ (5, BLOCK_FOR_INSN (code_label)->index);
+  ASSERT_EQ (NULL, LABEL_NAME (code_label));
+  ASSERT_EQ (1, LABEL_NUSES (code_label));
+
+  // 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 ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("jump-to-return.rtl"));
+
+  rtx_insn *jump_insn = get_insn_by_uid (1);
+  ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+  ASSERT_EQ (ret_rtx, JUMP_LABEL (jump_insn));
+  // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+}
+
+/* Verify that the loader copes with a jump_insn to a label_ref
+   marked "simple_return".  */
+
+static void
+test_loading_jump_to_simple_return ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION,
+		   locate_file ("jump-to-simple-return.rtl"));
+
+  rtx_insn *jump_insn = get_insn_by_uid (1);
+  ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+  ASSERT_EQ (simple_return_rtx, JUMP_LABEL (jump_insn));
+  // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+}
+
+/* Verify that the loader copes with a NOTE_INSN_BASIC_BLOCK.  */
+
+static void
+test_loading_note_insn_basic_block ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION,
+		   locate_file ("note_insn_basic_block.rtl"));
+
+  rtx_insn *note = get_insn_by_uid (1);
+  ASSERT_EQ (NOTE, GET_CODE (note));
+  ASSERT_EQ (2, BLOCK_FOR_INSN (note)->index);
+
+  ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (note));
+  ASSERT_EQ (2, NOTE_BASIC_BLOCK (note)->index);
+  ASSERT_EQ (BASIC_BLOCK_FOR_FN (cfun, 2), NOTE_BASIC_BLOCK (note));
+}
+
+/* Verify that the loader copes with a NOTE_INSN_DELETED.  */
+
+static void
+test_loading_note_insn_deleted ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("note-insn-deleted.rtl"));
+
+  rtx_insn *note = get_insn_by_uid (1);
+  ASSERT_EQ (NOTE, GET_CODE (note));
+  ASSERT_EQ (NOTE_INSN_DELETED, NOTE_KIND (note));
+}
+
+/* Verify that the const_int values are consolidated, since
+   pointer equality corresponds to value equality.
+   TODO: do this for all in CASE_CONST_UNIQUE.  */
+
+static void
+test_loading_const_int ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("const-int.rtl"));
+
+  /* Verify that const_int values below MAX_SAVED_CONST_INT use
+     the global values.  */
+  ASSERT_EQ (const0_rtx, SET_SRC (PATTERN (get_insn_by_uid (100))));
+  ASSERT_EQ (const1_rtx, SET_SRC (PATTERN (get_insn_by_uid (101))));
+  ASSERT_EQ (constm1_rtx, SET_SRC (PATTERN (get_insn_by_uid (102))));
+
+  /* Verify that other const_int values are consolidated. */
+  rtx int256 = gen_rtx_CONST_INT (SImode, 256);
+  ASSERT_EQ (int256, SET_SRC (PATTERN (get_insn_by_uid (103))));
+}
+
+/* Verify that the loader copes with a SYMBOL_REF.  */
+
+static void
+test_loading_symbol_ref ()
+{
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("symbol-ref.rtl"));
+
+  rtx_insn *insn = get_insn_by_uid (1045);
+
+  rtx high = SET_SRC (PATTERN (insn));
+  ASSERT_EQ (HIGH, GET_CODE (high));
+
+  rtx symbol_ref = XEXP (high, 0);
+  ASSERT_EQ (SYMBOL_REF, GET_CODE (symbol_ref));
+
+  /* Verify that "[flags 0xc0]" was parsed.  */
+  ASSERT_EQ (0xc0, SYMBOL_REF_FLAGS (symbol_ref));
+  /* TODO: we don't yet load SYMBOL_REF_DECL.  */
+}
+
+/* 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..5185960
--- /dev/null
+++ b/gcc/read-rtl-function.h
@@ -0,0 +1,56 @@
+/* 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
+
+/* 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 function_reader.  */
+
+struct function_reader_policy
+{
+  function_reader_policy (regno_remapper *regno_remapper_)
+  : m_regno_remapper (regno_remapper_)
+  {
+  }
+
+  regno_remapper *m_regno_remapper;
+};
+
+extern bool read_rtl_function_body (int argc, const char **argv,
+				    bool (*parse_opt) (const char *),
+				    function_reader_policy *policy);
+
+#endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 925ea45..3f42ce7 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,10 @@ htab_t subst_attr_to_iter_map = NULL;
 const char *current_iterator_name;
 
 static void validate_const_int (const char *);
-static rtx read_rtx_code (const char *);
-static void read_rtx_operand (rtx, int);
-static rtx read_nested_rtx (void);
-static rtx read_rtx_variadic (rtx);
+static void one_time_initialization (void);
+
+/* Global singleton.  */
+rtx_reader *rtx_reader_ptr = NULL;
 
 /* The mode and code iterator structures.  */
 static struct iterator_group modes, codes, ints, substs;
@@ -182,6 +193,8 @@ apply_int_iterator (void *loc, int value)
   *(int *)loc = value;
 }
 
+#ifdef GENERATOR_FILE
+
 /* This routine adds attribute or does nothing depending on VALUE.  When
    VALUE is 1, it does nothing - the first duplicate of original
    template is kept untouched when it's subjected to a define_subst.
@@ -253,6 +266,8 @@ bind_subst_iter_and_attr (const char *iter, const char *attr)
   *slot = value;
 }
 
+#endif /* #ifdef GENERATOR_FILE */
+
 /* Return name of a subst-iterator, corresponding to subst-attribute ATTR.  */
 
 static char*
@@ -419,6 +434,8 @@ copy_rtx_for_iterators (rtx original)
   return x;
 }
 
+#ifdef GENERATOR_FILE
+
 /* Return a condition that must satisfy both ORIGINAL and EXTRA.  If ORIGINAL
    has the form "&& ..." (as used in define_insn_and_splits), assume that
    EXTRA is already satisfied.  Empty strings are treated like "true".  */
@@ -582,6 +599,7 @@ apply_iterators (rtx original, vec<rtx> *queue)
 	}
     }
 }
+#endif /* #ifdef GENERATOR_FILE */
 
 /* Add a new "mapping" structure to hashtable TABLE.  NAME is the name
    of the mapping and GROUP is the group to which it belongs.  */
@@ -656,7 +674,9 @@ initialize_iterators (void)
   substs.iterators = htab_create (13, leading_string_hash,
 				 leading_string_eq_p, 0);
   substs.find_builtin = find_int; /* We don't use it, anyway.  */
+#ifdef GENERATOR_FILE
   substs.apply_iterator = apply_subst_iterator;
+#endif
 
   lower = add_mapping (&modes, modes.attrs, "mode");
   upper = add_mapping (&modes, modes.attrs, "MODE");
@@ -725,6 +745,8 @@ atoll (const char *p)
 }
 #endif
 
+
+#ifdef GENERATOR_FILE
 /* Process a define_conditions directive, starting with the optional
    space after the "define_conditions".  The directive looks like this:
 
@@ -766,6 +788,7 @@ read_conditions (void)
       add_c_test (expr, value);
     }
 }
+#endif /* #ifdef GENERATOR_FILE */
 
 static void
 validate_const_int (const char *string)
@@ -862,6 +885,8 @@ record_potential_iterator_use (struct iterator_group *group, void *ptr,
     }
 }
 
+#ifdef GENERATOR_FILE
+
 /* Finish reading a declaration of the form:
 
        (define... <name> [<value1> ... <valuen>])
@@ -1021,14 +1046,7 @@ check_code_iterator (struct mapping *iterator)
 bool
 read_rtx (const char *rtx_name, vec<rtx> *rtxen)
 {
-  static bool initialized = false;
-
-  /* Do one-time initialization.  */
-  if (!initialized)
-    {
-      initialize_iterators ();
-      initialized = true;
-    }
+  one_time_initialization ();
 
   /* Handle various rtx-related declarations that aren't themselves
      encoded as rtxes.  */
@@ -1076,22 +1094,118 @@ read_rtx (const char *rtx_name, vec<rtx> *rtxen)
       return true;
     }
 
-  apply_iterators (read_rtx_code (rtx_name), rtxen);
+  apply_iterators (rtx_reader_ptr->read_rtx_code (rtx_name), rtxen);
   iterator_uses.truncate (0);
   attribute_uses.truncate (0);
 
   return true;
 }
 
+#endif /* #ifdef GENERATOR_FILE */
+
+/* Do one-time initialization.  */
+
+static void
+one_time_initialization (void)
+{
+  static bool initialized = false;
+
+  if (!initialized)
+    {
+      initialize_iterators ();
+      initialized = true;
+    }
+}
+
+/* Consume characters until encountering a character in TERMINATOR_CHARS,
+   consuming the terminator character if CONSUME_TERMINATOR is true.
+   Return all characters before the terminator as an allocated buffer.  */
+
+char *
+rtx_reader::read_until (const char *terminator_chars, bool consume_terminator)
+{
+  int ch = read_skip_spaces ();
+  unread_char (ch);
+  auto_vec<char> buf;
+  while (1)
+    {
+      ch = read_char ();
+      if (strchr (terminator_chars, ch))
+	{
+	  if (!consume_terminator)
+	    unread_char (ch);
+	  break;
+	}
+      buf.safe_push (ch);
+    }
+  buf.safe_push ('\0');
+  return xstrdup (buf.address ());
+}
+
+/* Subroutine of read_rtx_code, for parsing zero or more flags.  */
+
+static void
+read_flags (rtx return_rtx)
+{
+  while (1)
+    {
+      int ch = read_char ();
+      if (ch != '/')
+	{
+	  unread_char (ch);
+	  break;
+	}
+
+      int flag_char = read_char ();
+      switch (flag_char)
+	{
+	  case 's':
+	    RTX_FLAG (return_rtx, in_struct) = 1;
+	    break;
+	  case 'v':
+	    RTX_FLAG (return_rtx, volatil) = 1;
+	    break;
+	  case 'u':
+	    RTX_FLAG (return_rtx, unchanging) = 1;
+	    break;
+	  case 'f':
+	    RTX_FLAG (return_rtx, frame_related) = 1;
+	    break;
+	  case 'j':
+	    RTX_FLAG (return_rtx, jump) = 1;
+	    break;
+	  case 'c':
+	    RTX_FLAG (return_rtx, call) = 1;
+	    break;
+	  case 'i':
+	    RTX_FLAG (return_rtx, return_val) = 1;
+	    break;
+	  default:
+	    fatal_with_file_and_line ("unrecognized flag: `%c'", flag_char);
+	}
+    }
+}
+
+/* FIXME. */
+
+static int
+parse_reg_note_name (const char *string)
+{
+  for (int i = 0; i < REG_NOTE_MAX; i++)
+    if (0 == strcmp (string, GET_REG_NOTE_NAME (i)))
+      return i;
+  fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
+}
+
 /* Subroutine of read_rtx and read_nested_rtx.  CODE_NAME is the name of
    either an rtx code or a code iterator.  Parse the rest of the rtx and
    return it.  */
 
-static rtx
-read_rtx_code (const char *code_name)
+rtx
+rtx_reader::read_rtx_code (const char *code_name)
 {
   RTX_CODE code;
-  struct mapping *iterator;
+  struct mapping *iterator = NULL;
   const char *format_ptr;
   struct md_name name;
   rtx return_rtx;
@@ -1104,13 +1218,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);
@@ -1121,6 +1241,25 @@ read_rtx_code (const char *code_name)
   if (iterator)
     record_iterator_use (iterator, return_rtx);
 
+  /* Check for flags. */
+  read_flags (return_rtx);
+
+  /* Read REG_NOTE names for EXPR_LIST and INSN_LIST.  */
+  if (GET_CODE (return_rtx) == EXPR_LIST
+      || GET_CODE (return_rtx) == INSN_LIST
+      || GET_CODE (return_rtx) == INT_LIST)
+    {
+      char ch = read_char ();
+      if (ch == ':')
+	{
+	  read_name (&name);
+	  PUT_MODE_RAW (return_rtx,
+			(machine_mode)parse_reg_note_name (name.string));
+	}
+      else
+	unread_char (ch);
+    }
+
   /* If what follows is `: mode ', read it and
      store the mode in the rtx.  */
 
@@ -1133,8 +1272,20 @@ read_rtx_code (const char *code_name)
   else
     unread_char (c);
 
+  if (INSN_CHAIN_CODE_P (code))
+    {
+      read_name (&name);
+      INSN_UID (return_rtx) = atoi (name.string);
+    }
+
+  /* Use the format_ptr to parse the various operands of this rtx.  */
   for (int idx = 0; format_ptr[idx] != 0; idx++)
-    read_rtx_operand (return_rtx, idx);
+    return_rtx = read_rtx_operand (return_rtx, idx);
+
+  /* Call a vfunc to handle the various additional information that
+     print-rtl.c can write after the regular fields; does nothing when
+     parsing .md files.  */
+  handle_any_trailing_information (return_rtx);
 
   if (CONST_WIDE_INT_P (return_rtx))
     {
@@ -1200,8 +1351,8 @@ read_rtx_code (const char *code_name)
    based on the corresponding format character within GET_RTX_FORMAT
    for the GET_CODE (RETURN_RTX).  */
 
-static void
-read_rtx_operand (rtx return_rtx, int idx)
+rtx
+rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
 {
   RTX_CODE code = GET_CODE (return_rtx);
   const char *format_ptr = GET_RTX_FORMAT (code);
@@ -1218,6 +1369,9 @@ read_rtx_operand (rtx return_rtx, int idx)
       break;
 
     case 'e':
+      XEXP (return_rtx, idx) = read_nested_rtx ();
+      break;
+
     case 'u':
       XEXP (return_rtx, idx) = read_nested_rtx ();
       break;
@@ -1293,7 +1447,10 @@ read_rtx_operand (rtx return_rtx, int idx)
 	star_if_braced = (format_ptr[idx] == 'T');
 
 	stringbuf = read_string (star_if_braced);
+	if (!stringbuf)
+	  break;
 
+#ifdef GENERATOR_FILE
 	/* For insn patterns, we want to provide a default name
 	   based on the file and line, like "*foo.md:12", if the
 	   given name is blank.  These are only for define_insn and
@@ -1304,7 +1461,7 @@ read_rtx_operand (rtx return_rtx, int idx)
 		|| GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
 	  {
 	    char line_name[20];
-	    const char *read_md_filename = rtx_reader_ptr->get_filename ();
+	    const char *read_md_filename = get_filename ();
 	    const char *fn = (read_md_filename ? read_md_filename : "rtx");
 	    const char *slash;
 	    for (slash = fn; *slash; slash ++)
@@ -1312,7 +1469,7 @@ read_rtx_operand (rtx return_rtx, int idx)
 		fn = slash + 1;
 	    obstack_1grow (&string_obstack, '*');
 	    obstack_grow (&string_obstack, fn, strlen (fn));
-	    sprintf (line_name, ":%d", rtx_reader_ptr->get_lineno ());
+	    sprintf (line_name, ":%d", get_lineno ());
 	    obstack_grow (&string_obstack, line_name, strlen (line_name)+1);
 	    stringbuf = XOBFINISH (&string_obstack, char *);
 	  }
@@ -1348,11 +1505,23 @@ read_rtx_operand (rtx return_rtx, int idx)
 	    if (m != 0)
 	      record_iterator_use (m, return_rtx);
 	  }
+#endif /* #ifdef GENERATOR_FILE */
+
+	/* "stringbuf" was allocated within string_obstack and thus has
+	   the its lifetime restricted to that of the rtx_reader.  This is
+	   OK for the generator programs, but for non-generator programs,
+	   XSTR and XTMPL fields are meant to be allocated in the GC-managed
+	   heap.  Hence we need to allocate a copy in the GC-managed heap
+	   for the non-generator case.  */
+	const char *string_ptr = stringbuf;
+#ifndef GENERATOR_FILE
+	string_ptr = ggc_strdup (stringbuf);
+#endif /* #ifndef GENERATOR_FILE */
 
 	if (star_if_braced)
-	  XTMPL (return_rtx, idx) = stringbuf;
+	  XTMPL (return_rtx, idx) = string_ptr;
 	else
-	  XSTR (return_rtx, idx) = stringbuf;
+	  XSTR (return_rtx, idx) = string_ptr;
       }
       break;
 
@@ -1398,12 +1567,14 @@ read_rtx_operand (rtx return_rtx, int idx)
     default:
       gcc_unreachable ();
     }
+
+  return return_rtx;
 }
 
 /* Read a nested rtx construct from the MD file and return it.  */
 
-static rtx
-read_nested_rtx (void)
+rtx
+rtx_reader::read_nested_rtx (void)
 {
   struct md_name name;
   rtx return_rtx;
@@ -1418,6 +1589,8 @@ read_nested_rtx (void)
 
   require_char_ws (')');
 
+  return_rtx = postprocess (return_rtx);
+
   return return_rtx;
 }
 
@@ -1427,8 +1600,8 @@ read_nested_rtx (void)
    When called, FORM is (thing x1 x2), and the file position
    is just past the leading parenthesis of x3.  Only works
    for THINGs which are dyadic expressions, e.g. AND, IOR.  */
-static rtx
-read_rtx_variadic (rtx form)
+rtx
+rtx_reader::read_rtx_variadic (rtx form)
 {
   char c = '(';
   rtx p = form, q;
@@ -1451,3 +1624,20 @@ read_rtx_variadic (rtx form)
   unread_char (c);
   return form;
 }
+
+/* FIXME.  */
+
+rtx_reader::rtx_reader ()
+: base_rtx_reader ()
+{
+  /* Set the global singleton pointer.  */
+  rtx_reader_ptr = this;
+}
+
+/* FIXME.  */
+
+rtx_reader::~rtx_reader ()
+{
+  /* Clear the global singleton pointer.  */
+  rtx_reader_ptr = NULL;
+}
diff --git a/gcc/rtl.h b/gcc/rtl.h
index ce1131b..169deb6 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..20d0b92
--- /dev/null
+++ b/gcc/selftest-rtl.c
@@ -0,0 +1,78 @@
+/* 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.
+   Read a dumped RTL function from PATH.
+   Use LOC as the effective location when reporting failures.  */
+
+rtl_dump_test::rtl_dump_test (const location &loc, const char *path,
+			      int dumped_first_pseudo_regno)
+: /* 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)
+{
+  function_reader_policy policy (&m_regno_remapper);
+
+  /* Parse the tempfile.  */
+  auto_vec<const char *> argv (2);
+  argv.safe_push (progname);
+  argv.safe_push (path);
+  bool read_ok
+    = read_rtl_function_body (argv.length (), argv.address (), NULL, &policy);
+  ASSERT_TRUE_AT (loc, read_ok);
+}
+
+/* Destructor for selftest::rtl_dump_test.
+   Cleanup global state relating to the function.  */
+
+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..b9cf605
--- /dev/null
+++ b/gcc/selftest-rtl.h
@@ -0,0 +1,65 @@
+/* A self-testing framework, for use by -fself-test.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_SELFTEST_RTL_H
+#define GCC_SELFTEST_RTL_H
+
+/* The selftest code should entirely disappear in a production
+   configuration, hence we guard all of it with #if CHECKING_P.  */
+
+#if CHECKING_P
+
+#include "read-rtl-function.h"
+
+namespace selftest {
+
+/* A class for testing RTL function dumps.
+   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 location &loc, const char *path,
+		 int dumped_first_pseudo_regno = 0);
+  ~rtl_dump_test ();
+
+  unsigned int effective_regno (int input_regno) const;
+
+ private:
+  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 ecc3d71..1dce665 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -70,6 +70,7 @@ selftest::run_tests ()
   tree_c_tests ();
   gimple_c_tests ();
   rtl_tests_c_tests ();
+  read_rtl_function_c_tests ();
 
   /* Higher-level tests, or for components that other selftests don't
      rely on.  */
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 8b9c007..ae39101 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -213,6 +213,7 @@ extern void hash_map_tests_c_tests ();
 extern void hash_set_tests_c_tests ();
 extern void input_c_tests ();
 extern void pretty_print_c_tests ();
+extern void read_rtl_function_c_tests ();
 extern void rtl_tests_c_tests ();
 extern void selftest_c_tests ();
 extern void spellcheck_c_tests ();
diff --git a/gcc/testsuite/selftests/asr_div1.rtl b/gcc/testsuite/selftests/asr_div1.rtl
new file mode 100644
index 0000000..689490d
--- /dev/null
+++ b/gcc/testsuite/selftests/asr_div1.rtl
@@ -0,0 +1,19 @@
+;; 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.  */
+
+(insn 8 0 9 2 (set (reg:DI 78)
+        (lshiftrt:DI (reg:DI 76)
+            (const_int 32 [0x20])))
+        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14
+        641 {*aarch64_lshr_sisd_or_int_di3}
+     (expr_list:REG_DEAD (reg:DI 76)
+        (nil)))
+(insn 9 8 0 2 (set (reg:SI 79)
+        (ashiftrt:SI (subreg:SI (reg:DI 78) 0)
+            (const_int 3 [0x3])))
+        ../../src/gcc/testsuite/gcc.dg/asr_div1.c:14
+        642 {*aarch64_ashr_sisd_or_int_si3}
+     (expr_list:REG_DEAD (reg:DI 78)
+        (nil)))
diff --git a/gcc/testsuite/selftests/const-int.rtl b/gcc/testsuite/selftests/const-int.rtl
new file mode 100644
index 0000000..4b016aa
--- /dev/null
+++ b/gcc/testsuite/selftests/const-int.rtl
@@ -0,0 +1,12 @@
+(insn 100 0 101 2
+  (set (reg:SI 100) (const_int 0 [0x0]))
+  test.c:2 -1 (nil))
+(insn 101 100 102 2
+  (set (reg:SI 101) (const_int 1 [0x1]))
+  test.c:2 -1 (nil))
+(insn 102 101 103 2
+  (set (reg:SI 102) (const_int -1 [0xffffffff]))
+  test.c:2 -1 (nil))
+(insn 103 102 0 2
+  (set (reg:SI 103) (const_int 256 [0x100]))
+  test.c:2 -1 (nil))
diff --git a/gcc/testsuite/selftests/copy-hard-reg-into-frame.rtl b/gcc/testsuite/selftests/copy-hard-reg-into-frame.rtl
new file mode 100644
index 0000000..f0357aa
--- /dev/null
+++ b/gcc/testsuite/selftests/copy-hard-reg-into-frame.rtl
@@ -0,0 +1,8 @@
+(insn 2 0 0 2
+  (set (mem/c:SI
+          (plus:DI
+            (reg/f:DI 20 frame)
+            (const_int -4 [0xfffffffffffffffc]))
+          [1 i+0 S4 A32])
+       (reg:SI 5 di [ i ])) test.c:2 -1
+     (nil))
diff --git a/gcc/testsuite/selftests/example-labels.rtl b/gcc/testsuite/selftests/example-labels.rtl
new file mode 100644
index 0000000..7c7fa4a
--- /dev/null
+++ b/gcc/testsuite/selftests/example-labels.rtl
@@ -0,0 +1,2 @@
+(code_label 1 0 2 6 3 (nil) [0 uses])
+(code_label 2 1 0 6 3 ("some_label_name") [57 uses])
diff --git a/gcc/testsuite/selftests/insn-with-mode.rtl b/gcc/testsuite/selftests/insn-with-mode.rtl
new file mode 100644
index 0000000..99d0d1d
--- /dev/null
+++ b/gcc/testsuite/selftests/insn-with-mode.rtl
@@ -0,0 +1 @@
+(insn:TI 31 0 0 2 (set (reg:SI 100) (reg:SI 101)) -1 (nil))
diff --git a/gcc/testsuite/selftests/jump-to-label-ref.rtl b/gcc/testsuite/selftests/jump-to-label-ref.rtl
new file mode 100644
index 0000000..0ecd62a
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-label-ref.rtl
@@ -0,0 +1,6 @@
+(jump_insn 1 0 2 4 (set (pc)
+        (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 3)
+(barrier 2 1 3)
+(code_label 3 2 0 5 2 (nil) [1 uses])
diff --git a/gcc/testsuite/selftests/jump-to-return.rtl b/gcc/testsuite/selftests/jump-to-return.rtl
new file mode 100644
index 0000000..d7802da
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-return.rtl
@@ -0,0 +1,6 @@
+(jump_insn 1 0 2 4 (set (pc)
+        (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> return)
+(barrier 2 1 3)
+(code_label 3 2 0 5 2 (nil) [1 uses])
diff --git a/gcc/testsuite/selftests/jump-to-simple-return.rtl b/gcc/testsuite/selftests/jump-to-simple-return.rtl
new file mode 100644
index 0000000..541dd4b
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-simple-return.rtl
@@ -0,0 +1,6 @@
+(jump_insn 1 0 2 4 (set (pc)
+        (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> simple_return)
+(barrier 2 1 3)
+(code_label 3 2 0 5 2 (nil) [1 uses])
diff --git a/gcc/testsuite/selftests/note-insn-deleted.rtl b/gcc/testsuite/selftests/note-insn-deleted.rtl
new file mode 100644
index 0000000..e63997f
--- /dev/null
+++ b/gcc/testsuite/selftests/note-insn-deleted.rtl
@@ -0,0 +1 @@
+(note 1 0 0 (nil) NOTE_INSN_DELETED)
diff --git a/gcc/testsuite/selftests/note_insn_basic_block.rtl b/gcc/testsuite/selftests/note_insn_basic_block.rtl
new file mode 100644
index 0000000..8e535a1
--- /dev/null
+++ b/gcc/testsuite/selftests/note_insn_basic_block.rtl
@@ -0,0 +1 @@
+(note 1 0 0 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
diff --git a/gcc/testsuite/selftests/symbol-ref.rtl b/gcc/testsuite/selftests/symbol-ref.rtl
new file mode 100644
index 0000000..bcf1ad1
--- /dev/null
+++ b/gcc/testsuite/selftests/symbol-ref.rtl
@@ -0,0 +1,3 @@
+(insn 1045 0 0 2 (set (reg:SI 480)
+        (high:SI (symbol_ref:SI ("isl_obj_map_vtable") [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>))) y.c:12702 -1
+     (nil))
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

