[PATCH 4/4] Initial version of RTL frontend

David Malcolm dmalcolm@redhat.com
Wed May 4 20:26:00 GMT 2016


This patch introduces the RTL frontend, along with an rtx_reader class.

The RTL frontend re-uses the existing code within read-md.c and read-rtl.c
to parse rtl dumps, which means compiling this code twice:
- once for the build machine, for building the various gen* tools
- once for the host machine, for the RTL frontend.

The second half of rtl.def is guarded within this clause:

  /* All expressions from this point forward appear only in machine
     descriptions.  */
  #ifdef GENERATOR_FILE
  ...etc..
  #endif /* GENERATOR_FILE */

hence lots of .md rtx codes simply don't exist when building for the
rtl frontend, requiring the addition of #ifdef GENERATOR_FILE in
various places in read-md.c and read-rtl.c.

The existing parser gets us most of the way there: much of the RTL
information is stored in operands described in the rtl.def format
strings.  However, print-rtl.c has lots of special-case code for
dumping other data, with a mish-mash of formats, so the patch contain
extra parsing code in read-rtl.c to read it in, or, at least, the
subset that I've encountered so far.

Some of the state for parsing .md/.rtl files is moved from being
globals to being fields of a new rtx_reader class, with a
function_reader subclass in the RTL frontend for the frontend-specific
behavior.

Various post-processing needs to happen after the rtx is loaded.
For example, the NEXT_INSN/PREV_INSN values are written to the dump
as integer values, but are stored as rtx_insn *; the relevant
instruction might not have be loaded yet.  All of this postprocessing
is recorded as a list of "fixup" objects within the function_reader,
with the fixups applied after all of the function is loaded.

The read-md.c/read-rtl.c code has its own diagnostic API (errors.h and
errors.c) for use by gen*.  This use printf-formatting, and doesn't
understand things like "%qs" used by our full diagnostic API.
For simplicitly the RTL frontend uses this "lite"/"diet" version of the
diagnostic API.  I have a version of the patch which makes it use the
full diagnostic API, but this seems to imply using libcpp and the full
diagnostic API when building the generator files, which makes for a
much more invasive patch.  Hence for simplicity I'm leaving this for
a followup.

I wrote this by compiling a test.c with -fdump-rtl-all on
x86_64-pc-linux-gnu, and then attempting to load the state at each
pass, and then trying to run just one pass, and fixing bugs until the
dump output from each pass was the same as when running the pass from
cc1.  I've only done this with a small subset of passes, and with a very
simple test case, so I'm sure there are plenty of bugs and "x86_64-isms"
remaining.

Known issues:
- There's no documentation for the RTL frontend.  Should there be?
- various FIXMEs and TODOs
- only tested so far on x86_64-pc-linux-gnu
- doesn't yet bootstrap (there seem to be some dependency issues in
  the Makefile)

gcc/ChangeLog:
	* cfgexpand.c (pass_expand::execute): Move some initializations
	to rtl_data::init_stack_alignment.
	(pass_expand::execute): Add true param to expand_function_start
	to enable emission of instructions.
	* emit-rtl.c (init_emit): Use ggc_cleared_vec_alloc when
	allocating regno_reg_rtx.
	* emit-rtl.h (rtl_data::init_stack_alignment): New method decl.
	* errors.c (error): Add "error: " to the error message.
	(fatal): Likewise.
	* errors.h (struct file_location): Move here from read-md.h.
	(file_location::file_location): Likewise.
	(error_at): New prototype.
	* function.c (instantiate_decls): Guard call to
	instantiate_decls_1 on DECL_INITIAL (fndecl) to non-NULL values.
	(expand_function_start): Add an "emit_insns" param, and guard
	all instruction emission with it.
	* function.h (expand_function_start): Likewise.
	* gcc.c (default_compilers): Add a ".rtl" entry.
	* genconstants.c (main): Update for conversion of read_md_files
	from a function to a method, via an instance of noop_reader.
	* genenums.c (main): Likewise.
	* genmddeps.c (main): Likewise.
	* genpreds.c (write_tm_constrs_h): Update for move of in_fname
	from a global to a field of rtx_reader.
	(write_tm_preds_h): Likewise.
	(write_insn_preds_c): Likewise.
	* gensupport.c (class gen_reader): New subclass of rtx_reader.
	(rtx_handle_directive): Convert from function to...
	(gen_reader::handle_unknown_directive): ...method.
	(init_rtx_reader_args_cb): Convert return type from bool to
	rtx_reader *.  Allocate a gen_reader instance, and use it to update
	call of read_md_files to a method call.  Return the allocated
	gen_reader instance if no errors occurred.
	init_rtx_reader_args): Convert return type from bool to
	rtx_reader *.
	* gensupport.h (init_rtx_reader_args_cb): Likewise.
	(init_rtx_reader_args_cb): Likewise.
	* print-rtl.c (print_rtx): When printing NULL string values,
	print " (nil)" rather than '""'.  When handling NULL basic blocks
	pointers, explicitly print " (nil)" rather than omitting the basic
	block information.
	* read-md.c (struct file_name_list): Move to class rtx_reader.
	(read_md_file): Move to field m_read_md_file of class rtx_reader.
	(read_md_lineno): Move to field m_read_md_lineno of class
	rtx_reader.
	(in_fname): Move to field m_toplevel_fname of class rtx_reader.
	(base_dir): Move to field m_base_dir of class rtx_reader.
	(first_dir_md_include): Move to field m_first_dir_md_include of
	class rtx_reader.
	(last_dir_md_include_ptr): Move to field m_last_dir_md_include_ptr
	of class rtx_reader.
	(max_include_len): Delete.
	(rtx_reader_ptr): New.
	(fatal_with_file_and_line): Print " error: " and " note:" in
	messages.  Update for move of read_md_filename and read_md_lineno
	into class rtx_reader.
	(read_skip_spaces): Allow '/' so that we can read filenames with
	paths.
	(require_char): New function.
	(require_char_ws): New function.
	(require_word_ws): New function.
	(rtx_reader::read_char): New method, based on old implementation
	of ::read_char in read-md.h.
	(rtx_reader::unread_char): Likewise, for ::unread_char.
	(peek_char): New function.
	(read_name): Move implementation into...
	(read_name_1): ...new function, and capture file location.
	(read_name_or_nil): New function.
	(read_escape): Update for move of globals into class rtx_reader.
	(read_braced_string): Likewise.
	(read_string): Likewise.  Also, handle "(nil)" by returning NULL.
	(handle_constants): Simplify by using require_char_ws.
	(handle_enum): Likewise.
	(rtx_reader::rtx_reader): New constructor.
	(rtx_reader::~rtx_reader): New destructor.
	(handle_include): Convert to...
	(file_location loc, directive_handler_t handle_directive)
	(rtx_reader::handle_include): ...method, moving directive_handler
	from a callback to a virtual function, and updating for move of
	globals to fields of rtx_reader.
	(handle_file): Convert to...
	(rtx_reader::handle_file): ...method, moving directive_handler
	from a callback to a virtual function, and updating for move of
	globals to fields of rtx_reader.
	(handle_toplevel_file): Convert to...
	(rtx_reader::handle_toplevel_file): ...method, moving
	directive_handler from a callback to a virtual function, and
	updating for move of globals to fields of rtx_reader.
	(rtx_reader::get_current_location): New.
	(parse_include): Convert to...
	(rtx_reader::add_include_path): ...method, updating for move of
	globals to fields of rtx_reader.
	(read_md_files): Convert to...
	(rtx_reader::read_md_files): ...method, moving directive_handler
	from a callback to a virtual function, updating for moves of
	global data to fields of rtx_reader, and for renaming of
	::parse_include to rtx_reader::add_include_path.
	(noop_reader::handle_unknown_directive): New virtual function.
	* read-md.h (struct file_location): Move to errors.h.
	(file_location::file_location): Likewise.
	(directive_handler_t): Delete typedef.
	(class rtx_reader): New class.
	(rtx_reader_ptr): New global.
	(class noop_reader): New class.
	(in_fname): Delete.
	(read_md_file): Delete.
	(read_md_lineno): Delete.
	(read_md_filename): Delete.
	(read_char): Reimplement in terms of rtx_reader::read_char.
	(unread_char): Reimplement in terms of rtx_reader::unread_char.
	(peek_char): New decl.
	(require_char): New decl.
	(require_char_ws): New decl.
	(require_word_ws): New decl.
	(read_name): Return a file_location.
	(read_name_or_nil): New decl.
	(read_md_files): Delete decl.
	* read-rtl.c: Conditionally include config.h or bconfig.h.  Include
	function.h and emit-rtl.h when built for the RTL frontend.
	(read_rtx_code): Remove "static" forward decl.
	(apply_subst_iterator): Guard 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 initialization of subst.apply_iterator
	with #ifdef GENERATOR_FILE.
	(read_conditions): Guard with #ifdef GENERATOR_FILE.  Simplify
	using require_char_ws.
	(read_mapping): Likewise.
	(add_define_attr_for_define_subst): Guard with
	#ifdef GENERATOR_FILE.
	(add_define_subst_attr): Likewise.
	(read_subst_mapping): Likewise.
	(check_code_iterator): Likewise.
	(read_rtx): Likewise.  Move one-time initialization into...
	(one_time_initialization): ...this 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.
	(read_rtx_code): Remove "static".  Call one_time_initialization.
	Initialize "iterator" to NULL and guard its use with
	#ifdef GENERATOR_FILE.  Call read_flags.  Read REG_NOTE names
	for EXPR_LIST, INSN_LIST and INT_LIST.  Read the INSN_UID of
	instructions.  For case '0', handle note-specific-data, and
	jump labels.  Handle case 'e'.  For case 'u', read the next/prev
	as an int, and add a fixup to turn it into a rtx_insn * later.
	For case 'E', simplify using require_char_ws.
	For cases 'S', 'T' and 's', handle NULL strings, and update for
	moving of read_md_file into class rtx_reader.
	For case 'w', strip away the redundant hex dump of the value.
	Handle cases 'i' and 'n' for the rtl frontend.
	Handle case 'B', allowing it to be "(nil)".
	For case 'r', handle the dump of ORIGINAL_REGNO and REG_EXPR.
	Handle the various additional information that print-rtl.c can
	write after the regular fields, for MEM and CODE_LABEL.
	(lookup_global_register): New function.
	(consolidate_reg): New function.
	(consolidate_singletons): New function.
	(read_nested_rtx): Simplify using require_char_ws.  Call
	consolidate_singletons.
	* rtl.c (in_rtl_frontend_p): New global.
	* rtl.h (read_rtx): Wrap decl with #ifdef GENERATOR_FILE.
	(read_rtx_code): New function decl.
	(in_rtl_frontend_p): New global decl.
	* toplev.c (compile_file): Bail out after the parse_file
	langhook if within the RTL frontend.
	* tree-dfa.c (ssa_default_def): Always NULL_TREE for the
	RTL frontend.

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

gcc/testsuite/ChangeLog:
	* lib/rtl-dg.exp: New file.
	* rtl.dg/dfinit.rtl: New file.
	* rtl.dg/final.rtl: New file.
	* rtl.dg/good-include.rtl: New file.
	* rtl.dg/good-includee.md: New file.
	* rtl.dg/into-cfglayout.rtl: New file.
	* rtl.dg/ira.rtl: New file.
	* rtl.dg/missing-include.rtl: New file.
	* rtl.dg/pro_and_epilogue.rtl: New file.
	* rtl.dg/roundtrip/code-labels.rtl: New file.
	* rtl.dg/roundtrip/frame-pointer.rtl: New file.
	* rtl.dg/roundtrip/insn-with-mode.rtl: New file.
	* rtl.dg/roundtrip/jump-to-label.rtl: New file.
	* rtl.dg/roundtrip/jump-to-return.rtl: New file.
	* rtl.dg/roundtrip/jump-to-simple-return.rtl: New file.
	* rtl.dg/roundtrip/note-insn-basic-block.rtl: New file.
	* rtl.dg/roundtrip/note-insn-deleted.rtl: New file.
	* rtl.dg/roundtrip/reg-with-orig-regno.rtl: New file.
	* rtl.dg/roundtrip/roundtrip.exp: New file.
	* rtl.dg/roundtrip/test-loop.cleaned.rtl: New file.
	* rtl.dg/roundtrip/test-switch-after-expand.rtl: New file.
	* rtl.dg/rtl.exp: New file.
	* rtl.dg/test.c: New file.
	* rtl.dg/unknown-insn-uid.rtl: New file.
	* rtl.dg/unknown-rtx-code.rtl: New file.
	* rtl.dg/vregs.rtl: New file.
---
 gcc/cfgexpand.c                                    |    7 +-
 gcc/emit-rtl.c                                     |   15 +-
 gcc/emit-rtl.h                                     |    2 +
 gcc/errors.c                                       |    4 +-
 gcc/errors.h                                       |   13 +
 gcc/function.c                                     |   41 +-
 gcc/function.h                                     |    2 +-
 gcc/gcc.c                                          |    1 +
 gcc/genconstants.c                                 |    3 +-
 gcc/genenums.c                                     |    3 +-
 gcc/genmddeps.c                                    |    3 +-
 gcc/genpreds.c                                     |    9 +-
 gcc/gensupport.c                                   |   29 +-
 gcc/gensupport.h                                   |    6 +-
 gcc/print-rtl.c                                    |    4 +-
 gcc/read-md.c                                      |  338 ++++--
 gcc/read-md.h                                      |  158 ++-
 gcc/read-rtl.c                                     |  670 ++++++++++-
 gcc/rtl.c                                          |    2 +
 gcc/rtl.h                                          |    4 +
 gcc/rtl/Make-lang.in                               |  148 +++
 gcc/rtl/config-lang.in                             |   36 +
 gcc/rtl/lang-specs.h                               |   25 +
 gcc/rtl/lang.opt                                   |   38 +
 gcc/rtl/notes.rst                                  |  201 ++++
 gcc/rtl/rtl-errors.c                               |   35 +
 gcc/rtl/rtl-frontend.c                             | 1219 ++++++++++++++++++++
 gcc/testsuite/lib/rtl-dg.exp                       |   64 +
 gcc/testsuite/rtl.dg/dfinit.rtl                    |   90 ++
 gcc/testsuite/rtl.dg/final.rtl                     |   51 +
 gcc/testsuite/rtl.dg/good-include.rtl              |    6 +
 gcc/testsuite/rtl.dg/good-includee.md              |    1 +
 gcc/testsuite/rtl.dg/into-cfglayout.rtl            |   85 ++
 gcc/testsuite/rtl.dg/ira.rtl                       |   84 ++
 gcc/testsuite/rtl.dg/missing-include.rtl           |    1 +
 gcc/testsuite/rtl.dg/pro_and_epilogue.rtl          |   38 +
 gcc/testsuite/rtl.dg/roundtrip/code-labels.rtl     |    2 +
 gcc/testsuite/rtl.dg/roundtrip/frame-pointer.rtl   |    4 +
 gcc/testsuite/rtl.dg/roundtrip/insn-with-mode.rtl  |    4 +
 gcc/testsuite/rtl.dg/roundtrip/jump-to-label.rtl   |    6 +
 gcc/testsuite/rtl.dg/roundtrip/jump-to-return.rtl  |    6 +
 .../rtl.dg/roundtrip/jump-to-simple-return.rtl     |    6 +
 .../rtl.dg/roundtrip/note-insn-basic-block.rtl     |    1 +
 .../rtl.dg/roundtrip/note-insn-deleted.rtl         |    1 +
 .../rtl.dg/roundtrip/reg-with-orig-regno.rtl       |    4 +
 gcc/testsuite/rtl.dg/roundtrip/roundtrip.exp       |   99 ++
 .../rtl.dg/roundtrip/test-loop.cleaned.rtl         |   75 ++
 .../rtl.dg/roundtrip/test-switch-after-expand.rtl  |  202 ++++
 gcc/testsuite/rtl.dg/rtl.exp                       |   43 +
 gcc/testsuite/rtl.dg/test.c                        |   31 +
 gcc/testsuite/rtl.dg/unknown-insn-uid.rtl          |    3 +
 gcc/testsuite/rtl.dg/unknown-rtx-code.rtl          |    1 +
 gcc/testsuite/rtl.dg/vregs.rtl                     |   80 ++
 gcc/toplev.c                                       |    7 +
 gcc/tree-dfa.c                                     |    5 +
 55 files changed, 3784 insertions(+), 232 deletions(-)
 create mode 100644 gcc/rtl/Make-lang.in
 create mode 100644 gcc/rtl/config-lang.in
 create mode 100644 gcc/rtl/lang-specs.h
 create mode 100644 gcc/rtl/lang.opt
 create mode 100644 gcc/rtl/notes.rst
 create mode 100644 gcc/rtl/rtl-errors.c
 create mode 100644 gcc/rtl/rtl-frontend.c
 create mode 100644 gcc/testsuite/lib/rtl-dg.exp
 create mode 100644 gcc/testsuite/rtl.dg/dfinit.rtl
 create mode 100644 gcc/testsuite/rtl.dg/final.rtl
 create mode 100644 gcc/testsuite/rtl.dg/good-include.rtl
 create mode 100644 gcc/testsuite/rtl.dg/good-includee.md
 create mode 100644 gcc/testsuite/rtl.dg/into-cfglayout.rtl
 create mode 100644 gcc/testsuite/rtl.dg/ira.rtl
 create mode 100644 gcc/testsuite/rtl.dg/missing-include.rtl
 create mode 100644 gcc/testsuite/rtl.dg/pro_and_epilogue.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/code-labels.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/frame-pointer.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/insn-with-mode.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/jump-to-label.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/jump-to-return.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/jump-to-simple-return.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/note-insn-basic-block.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/note-insn-deleted.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/reg-with-orig-regno.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/roundtrip.exp
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/test-loop.cleaned.rtl
 create mode 100644 gcc/testsuite/rtl.dg/roundtrip/test-switch-after-expand.rtl
 create mode 100644 gcc/testsuite/rtl.dg/rtl.exp
 create mode 100644 gcc/testsuite/rtl.dg/test.c
 create mode 100644 gcc/testsuite/rtl.dg/unknown-insn-uid.rtl
 create mode 100644 gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
 create mode 100644 gcc/testsuite/rtl.dg/vregs.rtl

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 21f21c9..4a62409 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -6187,10 +6187,7 @@ pass_expand::execute (function *fun)
   discover_nonconstant_array_refs ();
 
   targetm.expand_to_rtl_hook ();
-  crtl->stack_alignment_needed = STACK_BOUNDARY;
-  crtl->max_used_stack_slot_alignment = STACK_BOUNDARY;
-  crtl->stack_alignment_estimated = 0;
-  crtl->preferred_stack_boundary = STACK_BOUNDARY;
+  crtl->init_stack_alignment ();
   fun->cfg->max_jumptable_ents = 0;
 
   /* Resovle the function section.  Some targets, like ARM EABI rely on knowledge
@@ -6222,7 +6219,7 @@ pass_expand::execute (function *fun)
     }
 
   /* Set up parameters and prepare for return, for the function.  */
-  expand_function_start (current_function_decl);
+  expand_function_start (current_function_decl, true);
 
   /* If we emitted any instructions for setting up the variables,
      emit them before the FUNCTION_START note.  */
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 4e5ba41..c620032 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -5677,7 +5677,8 @@ init_emit (void)
   crtl->emit.regno_pointer_align
     = XCNEWVEC (unsigned char, crtl->emit.regno_pointer_align_length);
 
-  regno_reg_rtx = ggc_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
+  regno_reg_rtx =
+    ggc_cleared_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
 
   /* Put copies of all the hard registers into regno_reg_rtx.  */
   memcpy (regno_reg_rtx,
@@ -6295,5 +6296,17 @@ need_atomic_barrier_p (enum memmodel model, bool pre)
       gcc_unreachable ();
     }
 }
+
+/* Initialize fields of rtl_data related to stack alignment.  */
+
+void
+rtl_data::init_stack_alignment ()
+{
+  stack_alignment_needed = STACK_BOUNDARY;
+  max_used_stack_slot_alignment = STACK_BOUNDARY;
+  stack_alignment_estimated = 0;
+  preferred_stack_boundary = STACK_BOUNDARY;
+}
+
 
 #include "gt-emit-rtl.h"
diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h
index 39dfce9..80cb50d 100644
--- a/gcc/emit-rtl.h
+++ b/gcc/emit-rtl.h
@@ -55,6 +55,8 @@ struct GTY(()) incoming_args {
 
 /* Datastructures maintained for currently processed function in RTL form.  */
 struct GTY(()) rtl_data {
+  void init_stack_alignment ();
+
   struct expr_status expr;
   struct emit_status emit;
   struct varasm_status varasm;
diff --git a/gcc/errors.c b/gcc/errors.c
index 468384c..ba27319 100644
--- a/gcc/errors.c
+++ b/gcc/errors.c
@@ -61,7 +61,7 @@ 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);
@@ -78,7 +78,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);
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.c b/gcc/function.c
index 43a80b4..f856f87 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -1903,7 +1903,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))
@@ -5082,10 +5083,12 @@ stack_protect_epilogue (void)
    emitting RTL.
    SUBR is the FUNCTION_DECL node.
    PARMS_HAVE_CLEANUPS is nonzero if there are cleanups associated with
-   the function's parameters, which must be run at any return statement.  */
+   the function's parameters, which must be run at any return statement.
+   EMIT_INSNS is true if instructions are to emitted, false to avoid this
+   (for use by the RTL frontend).  */
 
 void
-expand_function_start (tree subr)
+expand_function_start (tree subr, bool emit_insns)
 {
   /* Make sure volatile mem refs aren't considered
      valid operands of arithmetic insns.  */
@@ -5101,7 +5104,8 @@ expand_function_start (tree subr)
   /* Make the label for return statements to jump to.  Do not special
      case machines with special return instructions -- they will be
      handled later during jump, ifcvt, or epilogue creation.  */
-  return_label = gen_label_rtx ();
+  if (emit_insns)
+    return_label = gen_label_rtx ();
 
   /* Initialize rtx used to return the value.  */
   /* Do this before assign_parms so that we copy the struct value address
@@ -5127,7 +5131,7 @@ expand_function_start (tree subr)
 	  /* Expect to be passed the address of a place to store the value.
 	     If it is passed as an argument, assign_parms will take care of
 	     it.  */
-	  if (sv)
+	  if (sv && emit_insns)
 	    {
 	      value_address = gen_reg_rtx (Pmode);
 	      emit_move_insn (value_address, sv);
@@ -5204,7 +5208,7 @@ expand_function_start (tree subr)
   assign_parms (subr);
 
   /* If function gets a static chain arg, store it.  */
-  if (cfun->static_chain_decl)
+  if (cfun->static_chain_decl && emit_insns)
     {
       tree parm = cfun->static_chain_decl;
       rtx local, chain;
@@ -5248,7 +5252,7 @@ expand_function_start (tree subr)
 
   /* If the function receives a non-local goto, then store the
      bits we need to restore the frame pointer.  */
-  if (cfun->nonlocal_goto_save_area)
+  if (cfun->nonlocal_goto_save_area && emit_insns)
     {
       tree t_save;
       rtx r_save;
@@ -5271,22 +5275,25 @@ expand_function_start (tree subr)
      The move is supposed to make sdb output more accurate.  */
   /* Indicate the beginning of the function body,
      as opposed to parm setup.  */
-  emit_note (NOTE_INSN_FUNCTION_BEG);
+  if (emit_insns)
+    {
+      emit_note (NOTE_INSN_FUNCTION_BEG);
 
-  gcc_assert (NOTE_P (get_last_insn ()));
+      gcc_assert (NOTE_P (get_last_insn ()));
 
-  parm_birth_insn = get_last_insn ();
+      parm_birth_insn = get_last_insn ();
 
-  if (crtl->profile)
-    {
+      if (crtl->profile)
+	{
 #ifdef PROFILE_HOOK
-      PROFILE_HOOK (current_function_funcdef_no);
+	  PROFILE_HOOK (current_function_funcdef_no);
 #endif
-    }
+	}
 
-  /* If we are doing generic stack checking, the probe should go here.  */
-  if (flag_stack_check == GENERIC_STACK_CHECK)
-    stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
+      /* If we are doing generic stack checking, the probe should go here.  */
+      if (flag_stack_check == GENERIC_STACK_CHECK)
+	stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
+    }
 }
 
 void
diff --git a/gcc/function.h b/gcc/function.h
index 501ef68..5272cbb 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -619,7 +619,7 @@ extern void pop_dummy_function (void);
 extern void init_dummy_function_start (void);
 extern void init_function_start (tree);
 extern void stack_protect_epilogue (void);
-extern void expand_function_start (tree);
+extern void expand_function_start (tree, bool);
 extern void expand_dummy_function_end (void);
 
 extern void thread_prologue_and_epilogue_insns (void);
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 1af5920..86cc32b 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1287,6 +1287,7 @@ static const struct compiler default_compilers[] =
   {".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0},
   {".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0},
   {".go", "#Go", 0, 1, 0},
+  {".rtl", "#RTL", 0, 1, 0},
   /* Next come the entries for C.  */
   {".c", "@c", 0, 0, 1},
   {"@c",
diff --git a/gcc/genconstants.c b/gcc/genconstants.c
index c10e3e3..e8be5b6 100644
--- a/gcc/genconstants.c
+++ b/gcc/genconstants.c
@@ -79,7 +79,8 @@ main (int argc, const char **argv)
 {
   progname = "genconstants";
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return (FATAL_EXIT_CODE);
 
   /* Initializing the MD reader has the side effect of loading up
diff --git a/gcc/genenums.c b/gcc/genenums.c
index db46a67..8af8d9a 100644
--- a/gcc/genenums.c
+++ b/gcc/genenums.c
@@ -49,7 +49,8 @@ main (int argc, const char **argv)
 {
   progname = "genenums";
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return (FATAL_EXIT_CODE);
 
   puts ("/* Generated automatically by the program `genenums'");
diff --git a/gcc/genmddeps.c b/gcc/genmddeps.c
index fd26a33..e3d229d 100644
--- a/gcc/genmddeps.c
+++ b/gcc/genmddeps.c
@@ -47,7 +47,8 @@ main (int argc, const char **argv)
   progname = "genmddeps";
   include_callback = add_filedep;
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return FATAL_EXIT_CODE;
 
   *last = NULL;
diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index dd7dbbf..ac03103 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -1204,7 +1204,8 @@ write_tm_constrs_h (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_CONSTRS_H\n\
@@ -1403,7 +1404,8 @@ write_tm_preds_h (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_PREDS_H\n\
@@ -1552,7 +1554,8 @@ write_insn_preds_c (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #include \"config.h\"\n\
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index 0eb4591..acf9ff6 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2226,10 +2226,18 @@ process_define_subst (void)
     }
 }
 
-/* A read_md_files callback for reading an rtx.  */
+/* A subclass of rtx_reader which reads .md files and calls process_rtx on
+   the top-level elements.  */
 
-static void
-rtx_handle_directive (file_location loc, const char *rtx_name)
+class gen_reader : public rtx_reader
+{
+ public:
+  gen_reader () : rtx_reader () {}
+  void handle_unknown_directive (file_location, const char *);
+};
+
+void
+gen_reader::handle_unknown_directive (file_location loc, const char *rtx_name)
 {
   auto_vec<rtx, 32> subrtxs;
   if (!read_rtx (rtx_name, &subrtxs))
@@ -2500,7 +2508,7 @@ check_define_attr_duplicates ()
 
 /* The entry point for initializing the reader.  */
 
-bool
+rtx_reader *
 init_rtx_reader_args_cb (int argc, const char **argv,
 			 bool (*parse_opt) (const char *))
 {
@@ -2516,7 +2524,8 @@ init_rtx_reader_args_cb (int argc, const char **argv,
   split_sequence_num = 1;
   peephole2_sequence_num = 1;
 
-  read_md_files (argc, argv, parse_opt, rtx_handle_directive);
+  gen_reader *reader = new gen_reader ();
+  reader->read_md_files (argc, argv, parse_opt);
 
   if (define_attr_queue != NULL)
     check_define_attr_duplicates ();
@@ -2532,12 +2541,18 @@ init_rtx_reader_args_cb (int argc, const char **argv,
   if (define_attr_queue != NULL)
     gen_mnemonic_attr ();
 
-  return !have_error;
+  if (have_error)
+    {
+      delete reader;
+      return NULL;
+    }
+
+  return reader;
 }
 
 /* Programs that don't have their own options can use this entry point
    instead.  */
-bool
+rtx_reader *
 init_rtx_reader_args (int argc, const char **argv)
 {
   return init_rtx_reader_args_cb (argc, argv, 0);
diff --git a/gcc/gensupport.h b/gcc/gensupport.h
index 645512c..618359d 100644
--- a/gcc/gensupport.h
+++ b/gcc/gensupport.h
@@ -125,9 +125,9 @@ struct optab_pattern
 };
 
 extern rtx add_implicit_parallel (rtvec);
-extern bool init_rtx_reader_args_cb (int, const char **,
-				     bool (*)(const char *));
-extern bool init_rtx_reader_args (int, const char **);
+extern rtx_reader *init_rtx_reader_args_cb (int, const char **,
+					    bool (*)(const char *));
+extern rtx_reader *init_rtx_reader_args (int, const char **);
 extern bool read_md_rtx (md_rtx_info *);
 extern unsigned int get_num_insn_codes ();
 
diff --git a/gcc/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 6c58878..584ace6 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -31,12 +31,6 @@ struct ptr_loc {
   int lineno;
 };
 
-/* A singly-linked list of filenames.  */
-struct file_name_list {
-  struct file_name_list *next;
-  const char *fname;
-};
-
 /* Obstack used for allocating MD strings.  */
 struct obstack string_obstack;
 
@@ -56,34 +50,13 @@ static htab_t joined_conditions;
 /* An obstack for allocating joined_conditions entries.  */
 static struct obstack joined_conditions_obstack;
 
-/* The file we are reading.  */
-FILE *read_md_file;
-
-/* The filename of READ_MD_FILE.  */
-const char *read_md_filename;
-
-/* The current line number in READ_MD_FILE.  */
-int read_md_lineno;
-
-/* The name of the toplevel file that indirectly included READ_MD_FILE.  */
-const char *in_fname;
-
-/* The directory part of IN_FNAME.  NULL if IN_FNAME is a bare filename.  */
-static char *base_dir;
-
-/* The first directory to search.  */
-static struct file_name_list *first_dir_md_include;
-
-/* A pointer to the null terminator of the md include chain.  */
-static struct file_name_list **last_dir_md_include_ptr = &first_dir_md_include;
-
 /* This callback will be invoked whenever an md include directive is
    processed.  To be used for creation of the dependency file.  */
 void (*include_callback) (const char *);
 
-/* The current maximum length of directory names in the search path
-   for include files.  (Altered as we get more of them.)  */
-static size_t max_include_len;
+/* Global singleton.  */
+
+rtx_reader *rtx_reader_ptr;
 
 /* A table of md_constant structures, hashed by name.  Null if no
    constant expansion should occur.  */
@@ -92,7 +65,7 @@ static htab_t md_constants;
 /* A table of enum_type structures, hashed by name.  */
 static htab_t enum_types;
 
-static void handle_file (directive_handler_t);
+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.  */
@@ -303,7 +276,8 @@ fatal_with_file_and_line (const char *msg, ...)
 
   va_start (ap, msg);
 
-  fprintf (stderr, "%s:%d: ", read_md_filename, read_md_lineno);
+  fprintf (stderr, "%s:%d: error: ", rtx_reader_ptr->get_filename (),
+	   rtx_reader_ptr->get_lineno ());
   vfprintf (stderr, msg, ap);
   putc ('\n', stderr);
 
@@ -322,8 +296,9 @@ fatal_with_file_and_line (const char *msg, ...)
     }
   context[i] = '\0';
 
-  fprintf (stderr, "%s:%d: following context is `%s'\n",
-	   read_md_filename, read_md_lineno, context);
+  fprintf (stderr, "%s:%d: note: following context is `%s'\n",
+	   rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+	   context);
 
   va_end (ap);
   exit (1);
@@ -372,7 +347,7 @@ read_skip_spaces (void)
 	    if (c != '*')
 	      {
 		unread_char (c);
-		fatal_with_file_and_line ("stray '/' in file");
+		return '/';
 	      }
 
 	    prevc = 0;
@@ -391,11 +366,76 @@ read_skip_spaces (void)
     }
 }
 
+/* Consume the next character, issuing a fatal error if it is not
+   EXPECTED.  */
+
+void require_char (char expected)
+{
+  int ch = read_char ();
+  if (ch != expected)
+    fatal_expected_char (expected, ch);
+}
+
+/* Consume any whitespace, then consume the next non-whitespace
+   character, issuing a fatal error if it is not EXPECTED.  */
+
+void require_char_ws (char expected)
+{
+  int ch = read_skip_spaces ();
+  if (ch != expected)
+    fatal_expected_char (expected, ch);
+}
+
+/* Consume any whitespace, then consume the next word (as per read_name),
+   issuing a fatal error if it is not EXPECTED.  */
+
+void require_word_ws (const char *expected)
+{
+  struct md_name name;
+  read_name (&name);
+  if (strcmp (name.string, expected))
+    fatal_with_file_and_line ("missing '%s'", expected);
+}
+
+/* Read the next character from the file.  */
+
+int
+rtx_reader::read_char (void)
+{
+  int ch;
+
+  ch = getc (m_read_md_file);
+  if (ch == '\n')
+    m_read_md_lineno++;
+
+  return ch;
+}
+
+/* Put back CH, which was the last character read from the file.  */
+
+void
+rtx_reader::unread_char (int ch)
+{
+  if (ch == '\n')
+    m_read_md_lineno--;
+  ungetc (ch, m_read_md_file);
+}
+
+/* Peek at the next character from the file without consuming it.  */
+
+int
+peek_char (void)
+{
+  int ch = read_char ();
+  unread_char (ch);
+  return ch;
+}
+
 /* Read an rtx code name into NAME.  It is terminated by any of the
    punctuation chars of rtx printed syntax.  */
 
-void
-read_name (struct md_name *name)
+static bool
+read_name_1 (struct md_name *name, file_location *out_loc)
 {
   int c;
   size_t i;
@@ -433,8 +473,12 @@ read_name (struct md_name *name)
       c = read_char ();
     }
 
+  unread_char (c);
+  *out_loc = rtx_reader_ptr->get_current_location ();
+  read_char ();
+
   if (i == 0)
-    fatal_with_file_and_line ("missing name or number");
+    return false;
 
   name->buffer[i] = 0;
   name->string = name->buffer;
@@ -455,6 +499,36 @@ read_name (struct md_name *name)
 	}
       while (def);
     }
+
+  return true;
+}
+
+/* Read an rtx code name into NAME.  It is terminated by any of the
+   punctuation chars of rtx printed syntax.  */
+
+file_location
+read_name (struct md_name *name)
+{
+  file_location loc;
+  if (!read_name_1 (name, &loc))
+    fatal_with_file_and_line ("missing name or number");
+  return loc;
+}
+
+file_location
+read_name_or_nil (struct md_name *name)
+{
+  file_location loc;
+  if (!read_name_1 (name, &loc))
+    {
+      file_location loc = rtx_reader_ptr->get_current_location ();
+      read_skip_construct (0, loc);
+      /* Skip the ')'.  */
+      read_char ();
+      name->buffer[0] = 0;
+      name->string = name->buffer;
+    }
+  return loc;
 }
 
 /* Subroutine of the string readers.  Handles backslash escapes.
@@ -501,7 +575,8 @@ read_escape (void)
       /* pass anything else through, but issue a warning.  */
     default:
       fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
-	       read_md_filename, read_md_lineno, c);
+	       rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+	       c);
       obstack_1grow (&string_obstack, '\\');
       break;
     }
@@ -544,7 +619,7 @@ read_braced_string (void)
 {
   int c;
   int brace_depth = 1;  /* caller-processed */
-  unsigned long starting_read_md_lineno = read_md_lineno;
+  unsigned long starting_read_md_lineno = rtx_reader_ptr->get_lineno ();
 
   obstack_1grow (&string_obstack, '{');
   while (brace_depth)
@@ -590,7 +665,7 @@ read_string (int star_if_braced)
       c = read_skip_spaces ();
     }
 
-  old_lineno = read_md_lineno;
+  old_lineno = rtx_reader_ptr->get_lineno ();
   if (c == '"')
     stringbuf = read_quoted_string ();
   else if (c == '{')
@@ -599,17 +674,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)
-    {
-      c = read_skip_spaces ();
-      if (c != ')')
-	fatal_expected_char (')', c);
-    }
+    require_char_ws (')');
 
-  set_md_ptr_loc (stringbuf, read_md_filename, old_lineno);
+  set_md_ptr_loc (stringbuf, rtx_reader_ptr->get_filename (), old_lineno);
   return stringbuf;
 }
 
@@ -764,9 +843,7 @@ handle_constants (void)
   int c;
   htab_t defs;
 
-  c = read_skip_spaces ();
-  if (c != '[')
-    fatal_expected_char ('[', c);
+  require_char_ws ('[');
 
   /* Disable constant expansion during definition processing.  */
   defs = md_constants;
@@ -782,9 +859,7 @@ handle_constants (void)
       read_name (&value);
       add_constant (defs, xstrdup (name.string), xstrdup (value.string), 0);
 
-      c = read_skip_spaces ();
-      if (c != ')')
-	fatal_expected_char (')', c);
+      require_char_ws (')');
     }
   md_constants = defs;
 }
@@ -846,9 +921,7 @@ handle_enum (file_location loc, bool md_p)
       *slot = def;
     }
 
-  c = read_skip_spaces ();
-  if (c != '[')
-    fatal_expected_char ('[', c);
+  require_char_ws ('[');
 
   while ((c = read_skip_spaces ()) != ']')
     {
@@ -900,13 +973,35 @@ traverse_enum_types (htab_trav callback, void *info)
   htab_traverse (enum_types, callback, info);
 }
 
+
+/* Constructor for rtx_reader.  */
+
+rtx_reader::rtx_reader ()
+: m_toplevel_fname (NULL),
+  m_read_md_filename (NULL),
+  m_read_md_lineno (0),
+  m_first_dir_md_include (NULL),
+  m_last_dir_md_include_ptr (&m_first_dir_md_include)
+{
+  /* Set the global singleton pointer.  */
+  rtx_reader_ptr = this;
+}
+
+/* rtx_reader's destructor.  */
+
+rtx_reader::~rtx_reader ()
+{
+  /* Clear the global singleton pointer.  */
+  rtx_reader_ptr = NULL;
+}
+
 /* Process an "include" directive, starting with the optional space
    after the "include".  Read in the file and use HANDLE_DIRECTIVE
    to process each unknown directive.  LINENO is the line number on
    which the "include" occurred.  */
 
-static void
-handle_include (file_location loc, directive_handler_t handle_directive)
+void
+rtx_reader::handle_include (file_location loc)
 {
   const char *filename;
   const char *old_filename;
@@ -923,7 +1018,7 @@ handle_include (file_location loc, directive_handler_t handle_directive)
       struct file_name_list *stackp;
 
       /* Search the directory path, trying to open the file.  */
-      for (stackp = first_dir_md_include; stackp; stackp = stackp->next)
+      for (stackp = m_first_dir_md_include; stackp; stackp = stackp->next)
 	{
 	  static const char sep[2] = { DIR_SEPARATOR, '\0' };
 
@@ -939,8 +1034,8 @@ handle_include (file_location loc, directive_handler_t handle_directive)
      filename with BASE_DIR.  */
   if (input_file == NULL)
     {
-      if (base_dir)
-	pathname = concat (base_dir, filename, NULL);
+      if (m_base_dir)
+	pathname = concat (m_base_dir, filename, NULL);
       else
 	pathname = xstrdup (filename);
       input_file = fopen (pathname, "r");
@@ -956,21 +1051,22 @@ handle_include (file_location loc, directive_handler_t handle_directive)
   /* Save the old cursor.  Note that the LINENO argument to this
      function is the beginning of the include statement, while
      read_md_lineno has already been advanced.  */
-  old_file = read_md_file;
-  old_filename = read_md_filename;
-  old_lineno = read_md_lineno;
+  old_file = m_read_md_file;
+  old_filename = m_read_md_filename;
+  old_lineno = m_read_md_lineno;
 
   if (include_callback)
     include_callback (pathname);
 
-  read_md_file = input_file;
-  read_md_filename = pathname;
-  handle_file (handle_directive);
+  m_read_md_file = input_file;
+  m_read_md_filename = pathname;
+
+  handle_file ();
 
   /* Restore the old cursor.  */
-  read_md_file = old_file;
-  read_md_filename = old_filename;
-  read_md_lineno = old_lineno;
+  m_read_md_file = old_file;
+  m_read_md_filename = old_filename;
+  m_read_md_lineno = old_lineno;
 
   /* Do not free the pathname.  It is attached to the various rtx
      queue elements.  */
@@ -980,16 +1076,16 @@ handle_include (file_location loc, directive_handler_t handle_directive)
    read_md_filename are valid.  Use HANDLE_DIRECTIVE to handle
    unknown directives.  */
 
-static void
-handle_file (directive_handler_t handle_directive)
+void
+rtx_reader::handle_file ()
 {
   struct md_name directive;
   int c;
 
-  read_md_lineno = 1;
+  m_read_md_lineno = 1;
   while ((c = read_skip_spaces ()) != EOF)
     {
-      file_location loc (read_md_filename, read_md_lineno);
+      file_location loc = get_current_location ();
       if (c != '(')
 	fatal_expected_char ('(', c);
 
@@ -1001,51 +1097,51 @@ handle_file (directive_handler_t handle_directive)
       else if (strcmp (directive.string, "define_c_enum") == 0)
 	handle_enum (loc, false);
       else if (strcmp (directive.string, "include") == 0)
-	handle_include (loc, handle_directive);
-      else if (handle_directive)
-	handle_directive (loc, directive.string);
+	handle_include (loc);
       else
-	read_skip_construct (1, loc);
+	handle_unknown_directive (loc, directive.string);
 
-      c = read_skip_spaces ();
-      if (c != ')')
-	fatal_expected_char (')', c);
+      require_char_ws (')');
     }
-  fclose (read_md_file);
+  fclose (m_read_md_file);
 }
 
-/* Like handle_file, but for top-level files.  Set up in_fname and
-   base_dir accordingly.  */
+/* Like handle_file, but for top-level files.  Set up m_toplevel_fname
+   and m_base_dir accordingly.  */
 
-static void
-handle_toplevel_file (directive_handler_t handle_directive)
+void
+rtx_reader::handle_toplevel_file ()
 {
   const char *base;
 
-  in_fname = read_md_filename;
-  base = lbasename (in_fname);
-  if (base == in_fname)
-    base_dir = NULL;
+  m_toplevel_fname = m_read_md_filename;
+  base = lbasename (m_toplevel_fname);
+  if (base == m_toplevel_fname)
+    m_base_dir = NULL;
   else
-    base_dir = xstrndup (in_fname, base - in_fname);
+    m_base_dir = xstrndup (m_toplevel_fname, base - m_toplevel_fname);
 
-  handle_file (handle_directive);
+  handle_file ();
+}
+
+file_location
+rtx_reader::get_current_location () const
+{
+  return file_location (m_read_md_filename, m_read_md_lineno);
 }
 
 /* Parse a -I option with argument ARG.  */
 
-static void
-parse_include (const char *arg)
+void
+rtx_reader::add_include_path (const char *arg)
 {
   struct file_name_list *dirtmp;
 
   dirtmp = XNEW (struct file_name_list);
   dirtmp->next = 0;
   dirtmp->fname = arg;
-  *last_dir_md_include_ptr = dirtmp;
-  last_dir_md_include_ptr = &dirtmp->next;
-  if (strlen (dirtmp->fname) > max_include_len)
-    max_include_len = strlen (dirtmp->fname);
+  *m_last_dir_md_include_ptr = dirtmp;
+  m_last_dir_md_include_ptr = &dirtmp->next;
 }
 
 /* The main routine for reading .md files.  Try to process all the .md
@@ -1055,16 +1151,11 @@ parse_include (const char *arg)
 
    PARSE_OPT, if nonnull, is passed all unknown command-line arguments.
    It should return true if it recognizes the argument or false if a
-   generic error should be reported.
-
-   If HANDLE_DIRECTIVE is nonnull, the parser calls it for each
-   unknown directive, otherwise it just skips such directives.
-   See the comment above the directive_handler_t definition for
-   details about the callback's interface.  */
+   generic error should be reported.  */
 
 bool
-read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
-	       directive_handler_t handle_directive)
+rtx_reader::read_md_files (int argc, const char **argv,
+			   bool (*parse_opt) (const char *))
 {
   int i;
   bool no_more_options;
@@ -1102,9 +1193,9 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 	if (argv[i][1] == 'I')
 	  {
 	    if (argv[i][2] != '\0')
-	      parse_include (argv[i] + 2);
+	      add_include_path (argv[i] + 2);
 	    else if (++i < argc)
-	      parse_include (argv[i]);
+	      add_include_path (argv[i]);
 	    else
 	      fatal ("directory name missing after -I option");
 	    continue;
@@ -1132,9 +1223,9 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 	      if (already_read_stdin)
 		fatal ("cannot read standard input twice");
 
-	      read_md_file = stdin;
-	      read_md_filename = "<stdin>";
-	      handle_toplevel_file (handle_directive);
+	      m_read_md_file = stdin;
+	      m_read_md_filename = "<stdin>";
+	      handle_toplevel_file ();
 	      already_read_stdin = true;
 	      continue;
 	    }
@@ -1150,14 +1241,14 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 
       /* If we get here we are looking at a non-option argument, i.e.
 	 a file to be processed.  */
-      read_md_filename = argv[i];
-      read_md_file = fopen (read_md_filename, "r");
-      if (read_md_file == 0)
+      m_read_md_filename = argv[i];
+      m_read_md_file = fopen (m_read_md_filename, "r");
+      if (m_read_md_file == 0)
 	{
-	  perror (read_md_filename);
+	  perror (m_read_md_filename);
 	  return false;
 	}
-      handle_toplevel_file (handle_directive);
+      handle_toplevel_file ();
       num_files++;
     }
 
@@ -1165,10 +1256,19 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
      read the standard input now.  */
   if (num_files == 0 && !already_read_stdin)
     {
-      read_md_file = stdin;
-      read_md_filename = "<stdin>";
-      handle_toplevel_file (handle_directive);
+      m_read_md_file = stdin;
+      m_read_md_filename = "<stdin>";
+      handle_toplevel_file ();
     }
 
   return !have_error;
 }
+
+/* class noop_reader : public rtx_reader */
+
+/* A dummy implementation which skips unknown directives.  */
+void
+noop_reader::handle_unknown_directive (file_location loc, const char *)
+{
+  read_skip_construct (1, loc);
+}
diff --git a/gcc/read-md.h b/gcc/read-md.h
index fc3b077..342a716 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,16 +79,122 @@ struct enum_type {
   unsigned int num_values;
 };
 
-/* A callback that handles a single .md-file directive, up to but not
-   including the closing ')'.  It takes two arguments: the file position
-   at which the directive started, and the name of the directive.  The next
-   unread character is the optional space after the directive name.  */
-typedef void (*directive_handler_t) (file_location, const char *);
+class rtx_reader
+{
+ public:
+  rtx_reader ();
+  virtual ~rtx_reader ();
+
+  bool read_md_files (int, const char **, bool (*) (const char *));
+
+  /* A hook that handles a single .md-file directive, up to but not
+     including the closing ')'.  It takes two arguments: the file position
+     at which the directive started, and the name of the directive.  The next
+     unread character is the optional space after the directive name.  */
+  virtual void handle_unknown_directive (file_location, const char *) = 0;
+
+  /* A hook for the RTL frontend to override, to record insn UIDs for later
+     fixup.  */
+  virtual void add_fixup_insn_uid (file_location /*loc*/, rtx /*insn*/,
+				   int /*operand_idx*/, int /*insn_uid*/)
+  {}
+
+  /* A hook for the RTL frontend to override, to record basic block IDs
+     for later fixup.  */
+  virtual void add_fixup_bb (file_location /*loc*/, rtx /*insn*/,
+			     int /*operand_idx*/, int /*bb_idx*/)
+  {}
+
+  /* A hook for the RTL frontend to override, to record basic block IDs
+     for fixup of NOTE_INSN_BASIC_BLOCK.  */
+  virtual void add_fixup_note_insn_basic_block (file_location /*loc*/,
+						rtx /*insn*/,
+						int /*operand_idx*/,
+						int /*bb_idx*/)
+  {}
+
+  /* A hook for the RTL frontend to override, to record source location
+     information for fixing up into location_t values. */
+  virtual void add_fixup_source_location (file_location /*loc*/, rtx /*insn*/,
+					  int /*operand_idx*/,
+					  const char */*filename*/,
+					  int /*lineno*/)
+  {}
+
+  /* A hook for the RTL frontend to override, to record label names
+     for fixing up the JUMP_LABEL of an insn.  */
+  virtual void add_fixup_jump_label (file_location /*loc*/, rtx /*insn*/,
+				     int /*operand_idx*/,
+				     const char */*label*/)
+  {}
+
+  /* A hook for the RTL frontend to override, to record textual tree
+     dumps for fix up the expr of an rtx (REG or MEM).  */
+  virtual void add_fixup_expr (file_location /*loc*/, rtx /*x*/,
+			       const char */*desc*/)
+  {}
+
+  file_location get_current_location () const;
+
+  int read_char (void);
+  void unread_char (int ch);
+
+  const char *get_top_level_filename () const { return m_toplevel_fname; }
+  const char *get_filename () const { return m_read_md_filename; }
+  int get_lineno () const { return m_read_md_lineno; }
+
+ private:
+  /* A singly-linked list of filenames.  */
+  struct file_name_list {
+    struct file_name_list *next;
+    const char *fname;
+  };
+
+ private:
+  void handle_file ();
+  void handle_toplevel_file ();
+  void handle_include (file_location loc);
+  void add_include_path (const char *arg);
+
+ private:
+  /* The name of the toplevel file that indirectly included
+     m_read_md_file.  */
+  const char *m_toplevel_fname;
+
+  /* The directory part of m_toplevel_fname
+     NULL if m_toplevel_fname is a bare filename.  */
+  char *m_base_dir;
+
+  /* The file we are reading.  */
+  FILE *m_read_md_file;
+
+  /* The filename of m_read_md_file.  */
+  const char *m_read_md_filename;
+
+  /* The current line number in m_read_md_file.  */
+  int m_read_md_lineno;
+
+  /* The first directory to search.  */
+  file_name_list *m_first_dir_md_include;
+
+  /* A pointer to the null terminator of the md include chain.  */
+  file_name_list **m_last_dir_md_include_ptr;
+};
+
+/* Global singleton.  */
+extern rtx_reader *rtx_reader_ptr;
+
+/* An rtx_reader subclass which skips unknown directives.  */
+
+class noop_reader : public rtx_reader
+{
+ public:
+  noop_reader () : rtx_reader () {}
+
+  /* A dummy implementation which skips unknown directives.  */
+  void handle_unknown_directive (file_location, const char *);
+};
 
-extern const char *in_fname;
-extern FILE *read_md_file;
-extern int read_md_lineno;
-extern const char *read_md_filename;
 extern struct obstack string_obstack;
 extern void (*include_callback) (const char *);
 
@@ -108,12 +203,7 @@ extern void (*include_callback) (const char *);
 static inline int
 read_char (void)
 {
-  int ch;
-
-  ch = getc (read_md_file);
-  if (ch == '\n')
-    read_md_lineno++;
-  return ch;
+  return rtx_reader_ptr->read_char ();
 }
 
 /* Put back CH, which was the last character read from the MD file.  */
@@ -121,11 +211,11 @@ read_char (void)
 static inline void
 unread_char (int ch)
 {
-  if (ch == '\n')
-    read_md_lineno--;
-  ungetc (ch, read_md_file);
+  rtx_reader_ptr->unread_char (ch);
 }
 
+extern int peek_char (void);
+
 extern hashval_t leading_string_hash (const void *);
 extern int leading_string_eq_p (const void *, const void *);
 extern void copy_md_ptr_loc (const void *, const void *);
@@ -141,7 +231,11 @@ extern void fatal_with_file_and_line (const char *, ...)
   ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
 extern void fatal_expected_char (int, int) ATTRIBUTE_NORETURN;
 extern int read_skip_spaces (void);
-extern void read_name (struct md_name *);
+extern void require_char (char expected);
+extern void require_char_ws (char expected);
+extern void require_word_ws (const char *expected);
+extern file_location read_name (struct md_name *);
+extern file_location read_name_or_nil (struct md_name *);
 extern char *read_quoted_string (void);
 extern char *read_string (int);
 extern int n_comma_elts (const char *);
@@ -150,7 +244,5 @@ extern void upcase_string (char *);
 extern void traverse_md_constants (htab_trav, void *);
 extern void traverse_enum_types (htab_trav, void *);
 extern struct enum_type *lookup_enum_type (const char *);
-extern bool read_md_files (int, const char **, bool (*) (const char *),
-			   directive_handler_t);
 
 #endif /* GCC_READ_MD_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 79f42bf..202898b 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,7 +117,7 @@ htab_t subst_attr_to_iter_map = NULL;
 const char *current_iterator_name;
 
 static void validate_const_int (const char *);
-static rtx read_rtx_code (const char *);
+static void one_time_initialization (void);
 static rtx read_nested_rtx (void);
 static rtx read_rtx_variadic (rtx);
 
@@ -181,6 +192,8 @@ apply_int_iterator (void *loc, int value)
   *(int *)loc = value;
 }
 
+#ifdef GENERATOR_FILE
+
 /* This routine adds attribute or does nothing depending on VALUE.  When
    VALUE is 1, it does nothing - the first duplicate of original
    template is kept untouched when it's subjected to a define_subst.
@@ -252,6 +265,8 @@ bind_subst_iter_and_attr (const char *iter, const char *attr)
   *slot = value;
 }
 
+#endif /* #ifdef GENERATOR_FILE */
+
 /* Return name of a subst-iterator, corresponding to subst-attribute ATTR.  */
 
 static char*
@@ -418,6 +433,8 @@ copy_rtx_for_iterators (rtx original)
   return x;
 }
 
+#ifdef GENERATOR_FILE
+
 /* Return a condition that must satisfy both ORIGINAL and EXTRA.  If ORIGINAL
    has the form "&& ..." (as used in define_insn_and_splits), assume that
    EXTRA is already satisfied.  Empty strings are treated like "true".  */
@@ -581,6 +598,7 @@ apply_iterators (rtx original, vec<rtx> *queue)
 	}
     }
 }
+#endif /* #ifdef GENERATOR_FILE */
 
 /* Add a new "mapping" structure to hashtable TABLE.  NAME is the name
    of the mapping and GROUP is the group to which it belongs.  */
@@ -655,7 +673,9 @@ initialize_iterators (void)
   substs.iterators = htab_create (13, leading_string_hash,
 				 leading_string_eq_p, 0);
   substs.find_builtin = find_int; /* We don't use it, anyway.  */
+#ifdef GENERATOR_FILE
   substs.apply_iterator = apply_subst_iterator;
+#endif
 
   lower = add_mapping (&modes, modes.attrs, "mode");
   upper = add_mapping (&modes, modes.attrs, "MODE");
@@ -724,6 +744,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:
 
@@ -742,9 +764,7 @@ read_conditions (void)
 {
   int c;
 
-  c = read_skip_spaces ();
-  if (c != '[')
-    fatal_expected_char ('[', c);
+  require_char_ws ('[');
 
   while ( (c = read_skip_spaces ()) != ']')
     {
@@ -759,18 +779,15 @@ read_conditions (void)
       validate_const_int (name.string);
       value = atoi (name.string);
 
-      c = read_skip_spaces ();
-      if (c != '"')
-	fatal_expected_char ('"', c);
+      require_char_ws ('"');
       expr = read_quoted_string ();
 
-      c = read_skip_spaces ();
-      if (c != ')')
-	fatal_expected_char (')', c);
+      require_char_ws (')');
 
       add_c_test (expr, value);
     }
 }
+#endif /* #ifdef GENERATOR_FILE */
 
 static void
 validate_const_int (const char *string)
@@ -867,6 +884,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>])
@@ -890,9 +909,7 @@ read_mapping (struct iterator_group *group, htab_t table)
   read_name (&name);
   m = add_mapping (group, table, name.string);
 
-  c = read_skip_spaces ();
-  if (c != '[')
-    fatal_expected_char ('[', c);
+  require_char_ws ('[');
 
   /* Read each value.  */
   end_ptr = &m->values;
@@ -912,9 +929,7 @@ read_mapping (struct iterator_group *group, htab_t table)
 	  /* A "(name string)" pair.  */
 	  read_name (&name);
 	  string = read_string (false);
-	  c = read_skip_spaces ();
-	  if (c != ')')
-	    fatal_expected_char (')', c);
+	  require_char_ws (')');
 	}
       number = group->find_builtin (name.string);
       end_ptr = add_map_value (end_ptr, number, string);
@@ -1030,14 +1045,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.  */
@@ -1092,16 +1100,187 @@ read_rtx (const char *rtx_name, vec<rtx> *rtxen)
   return true;
 }
 
+#endif /* #ifdef GENERATOR_FILE */
+
+/* Do one-time initialization.  */
+
+static void
+one_time_initialization (void)
+{
+  static bool initialized = false;
+
+  if (!initialized)
+    {
+      initialize_iterators ();
+      initialized = true;
+    }
+}
+
+#ifndef GENERATOR_FILE
+static int
+parse_reg_note_name (const char *string)
+{
+  for (int i = 0; i < REG_NOTE_MAX; i++)
+    if (0 == strcmp (string, GET_REG_NOTE_NAME (i)))
+      return i;
+  fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
+}
+
+static int
+parse_note_insn_name (const char *string)
+{
+  for (int i = 0; i < NOTE_INSN_MAX; i++)
+    if (0 == strcmp (string, GET_NOTE_INSN_NAME (i)))
+      return i;
+  fatal_with_file_and_line ("unrecognized NOTE_INSN name: `%s'", string);
+}
+
+/* Handle the optional location information written by print_rtx for
+   instructions.  Specifically, operand 4 of instructions (of type "i')
+   is printed thus:
+
+     if (INSN_HAS_LOCATION (in_insn))
+       {
+	 expanded_location xloc = insn_location (in_insn);
+	 fprintf (outfile, " %s:%i", xloc.file, xloc.line);
+       }
+
+    Hence we need to speculatively read a location of the form
+    " %s:%i", and unread the content if there wasn't one.
+
+    Assume that filenames can't contain whitespace, and can't
+    contain ':'.  */
+
+void maybe_read_location (int operand_idx, rtx insn)
+{
+  file_location loc = rtx_reader_ptr->get_current_location ();
+
+  /* Skip to first non-whitespace.  */
+  int ch = read_skip_spaces ();
+  auto_vec<char> buf;
+  buf.safe_push (ch);
+  while (1)
+    {
+      int ch = read_char ();
+      /* If we see a ':', assume we have a filename.  */
+      if (ch == ':')
+	{
+	  buf.safe_push ('\0');
+	  break;
+	}
+      buf.safe_push (ch);
+
+      /* If we see a space before ':', assume we don't have a
+	 filename.  */
+      if (ISSPACE (ch))
+	{
+	  while (!buf.is_empty ())
+	    unread_char (buf.pop ());
+	  return;
+	}
+    }
+  char *filename = buf.address ();
+  struct md_name name;
+  read_name (&name);
+
+  rtx_reader_ptr->add_fixup_source_location (loc, insn, operand_idx,
+					     filename, atoi(name.string));
+}
+
+/* Consume characters until encountering a character in TERMINATOR_CHARS,
+   consuming the terminator character if CONSUME_TERMINATOR is true.
+   Return all characters before the terminator as an allocated buffer.  */
+
+static char *
+read_until (const char *terminator_chars, bool consume_terminator)
+{
+  int ch = read_skip_spaces ();
+  unread_char (ch);
+  auto_vec<char> buf;
+  while (1)
+    {
+      ch = read_char ();
+      if (strchr (terminator_chars, ch))
+	{
+	  if (!consume_terminator)
+	    unread_char (ch);
+	  break;
+	}
+      buf.safe_push (ch);
+    }
+  buf.safe_push ('\0');
+  return xstrdup (buf.address ());
+}
+
+static void strip_trailing_whitespace (char *desc)
+{
+  char *terminator = desc + strlen (desc);
+  while (desc < terminator)
+    {
+      terminator--;
+      if (ISSPACE (*terminator))
+	*terminator = '\0';
+      else
+	break;
+    }
+}
+
+#endif /* #ifndef GENERATOR_FILE */
+
+/* Subroutine of read_rtx_code, for parsing zero or more flags.  */
+
+static void
+read_flags (rtx return_rtx)
+{
+  while (1)
+    {
+      int ch = read_char ();
+      if (ch != '/')
+	{
+	  unread_char (ch);
+	  break;
+	}
+
+      int flag_char = read_char ();
+      switch (flag_char)
+	{
+	  case 's':
+	    RTX_FLAG (return_rtx, in_struct) = 1;
+	    break;
+	  case 'v':
+	    RTX_FLAG (return_rtx, volatil) = 1;
+	    break;
+	  case 'u':
+	    RTX_FLAG (return_rtx, unchanging) = 1;
+	    break;
+	  case 'f':
+	    RTX_FLAG (return_rtx, frame_related) = 1;
+	    break;
+	  case 'j':
+	    RTX_FLAG (return_rtx, jump) = 1;
+	    break;
+	  case 'c':
+	    RTX_FLAG (return_rtx, call) = 1;
+	    break;
+	  case 'i':
+	    RTX_FLAG (return_rtx, return_val) = 1;
+	    break;
+	  default:
+	    fatal_with_file_and_line ("unrecognized flag: `%c'", flag_char);
+	}
+    }
+}
+
 /* Subroutine of read_rtx and read_nested_rtx.  CODE_NAME is the name of
    either an rtx code or a code iterator.  Parse the rest of the rtx and
    return it.  */
 
-static rtx
+rtx
 read_rtx_code (const char *code_name)
 {
   int i;
   RTX_CODE code;
-  struct mapping *iterator, *m;
+  struct mapping *iterator = NULL, *m;
   const char *format_ptr;
   struct md_name name;
   rtx return_rtx;
@@ -1118,13 +1297,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);
@@ -1135,6 +1320,27 @@ read_rtx_code (const char *code_name)
   if (iterator)
     record_iterator_use (iterator, return_rtx);
 
+  /* Check for flags. */
+  read_flags (return_rtx);
+
+  /* Read REG_NOTE names for EXPR_LIST and INSN_LIST.  */
+#ifndef GENERATOR_FILE
+  if (GET_CODE (return_rtx) == EXPR_LIST
+      || GET_CODE (return_rtx) == INSN_LIST
+      || GET_CODE (return_rtx) == INT_LIST)
+    {
+      char ch = read_char ();
+      if (ch == ':')
+	{
+	  read_name (&name);
+	  PUT_MODE_RAW (return_rtx,
+			(machine_mode)parse_reg_note_name (name.string));
+	}
+      else
+	unread_char (ch);
+    }
+#endif
+
   /* If what follows is `: mode ', read it and
      store the mode in the rtx.  */
 
@@ -1147,6 +1353,12 @@ read_rtx_code (const char *code_name)
   else
     unread_char (i);
 
+  if (INSN_CHAIN_CODE_P (code))
+    {
+      read_name (&name);
+      INSN_UID (return_rtx) = atoi (name.string);
+    }
+
   for (i = 0; format_ptr[i] != 0; i++)
     switch (format_ptr[i])
       {
@@ -1155,11 +1367,65 @@ read_rtx_code (const char *code_name)
       case '0':
 	if (code == REG)
 	  ORIGINAL_REGNO (return_rtx) = REGNO (return_rtx);
+	else if (i == 3 && code == NOTE)
+	  {
+	    /* Note-specific data appears for operand 3, which annoyingly
+	       is before the enum specifying which kind of note we have
+	       (operand 4).  */
+#ifndef GENERATOR_FILE
+	    c = read_skip_spaces ();
+	    if (c == '[')
+	      {
+		/* Possibly data for a NOTE_INSN_BASIC_BLOCK, of the form:
+		   [bb %d].  */
+		file_location bb_loc = read_name (&name);
+		if (strcmp (name.string, "bb"))
+		  error_at (bb_loc, "was expecting `%s'", "bb");
+		read_name (&name);
+		int bb_idx = atoi (name.string);
+		rtx_reader_ptr->add_fixup_note_insn_basic_block (bb_loc,
+								 return_rtx, i,
+								 bb_idx);
+		require_char_ws (']');
+	      }
+	    else
+	      unread_char (c);
+#endif /* #ifndef GENERATOR_FILE */
+	  }
+	else if (i == 7 && JUMP_P (return_rtx))
+	  {
+#ifndef GENERATOR_FILE
+	    c = read_skip_spaces ();
+	    if (c != '-')
+	      {
+		unread_char (c);
+		break;
+	      }
+	    require_char ('>');
+	    file_location loc = read_name (&name);
+	    rtx_reader_ptr->add_fixup_jump_label (loc, return_rtx, i, name.string);
+#endif /* #ifndef GENERATOR_FILE */
+	  }
 	break;
 
       case 'e':
+	XEXP (return_rtx, i) = read_nested_rtx ();
+	break;
+
       case 'u':
+#ifdef GENERATOR_FILE
 	XEXP (return_rtx, i) = read_nested_rtx ();
+#else
+	{
+	  /* The RTL file recorded the ID of an insn (or 0 for NULL); we
+	     must store this as a pointer, but the insn might not have
+	     been loaded yet.  Store the ID away for now.  */
+	  file_location loc = read_name (&name);
+	  int insn_id = atoi (name.string);
+	  if (insn_id)
+	    rtx_reader_ptr->add_fixup_insn_uid (loc, return_rtx, i, insn_id);
+	}
+#endif
 	break;
 
       case 'V':
@@ -1181,9 +1447,7 @@ read_rtx_code (const char *code_name)
 	  int list_counter = 0;
 	  rtvec return_vec = NULL_RTVEC;
 
-	  c = read_skip_spaces ();
-	  if (c != '[')
-	    fatal_expected_char ('[', c);
+	  require_char_ws ('[');
 
 	  /* Add expressions to a list, while keeping a count.  */
 	  obstack_init (&vector_stack);
@@ -1234,7 +1498,10 @@ read_rtx_code (const char *code_name)
 	  star_if_braced = (format_ptr[i] == 'T');
 
 	  stringbuf = read_string (star_if_braced);
+	  if (!stringbuf)
+	    break;
 
+#ifdef GENERATOR_FILE
 	  /* For insn patterns, we want to provide a default name
 	     based on the file and line, like "*foo.md:12", if the
 	     given name is blank.  These are only for define_insn and
@@ -1245,6 +1512,7 @@ read_rtx_code (const char *code_name)
 		  || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
 	    {
 	      char line_name[20];
+	      const char *read_md_filename = rtx_reader_ptr->get_filename ();
 	      const char *fn = (read_md_filename ? read_md_filename : "rtx");
 	      const char *slash;
 	      for (slash = fn; *slash; slash ++)
@@ -1252,10 +1520,11 @@ read_rtx_code (const char *code_name)
 		  fn = slash + 1;
 	      obstack_1grow (&string_obstack, '*');
 	      obstack_grow (&string_obstack, fn, strlen (fn));
-	      sprintf (line_name, ":%d", read_md_lineno);
+	      sprintf (line_name, ":%d", rtx_reader_ptr->get_lineno ());
 	      obstack_grow (&string_obstack, line_name, strlen (line_name)+1);
 	      stringbuf = XOBFINISH (&string_obstack, char *);
 	    }
+#endif /* #ifdef GENERATOR_FILE */
 
 	  /* Find attr-names in the string.  */
 	  ptr = &tmpstr[0];
@@ -1311,14 +1580,57 @@ read_rtx_code (const char *code_name)
 #endif
 #endif
 	XWINT (return_rtx, i) = tmp_wide;
+#ifndef GENERATOR_FILE
+	/* Strip away the redundant hex dump of the value.  */
+	{
+	  require_char_ws ('[');
+	  read_name (&name);
+	  require_char_ws (']');
+	}
+#endif
 	break;
 
       case 'i':
       case 'n':
+#ifdef GENERATOR_FILE
 	/* Can be an iterator or an integer constant.  */
 	read_name (&name);
 	record_potential_iterator_use (&ints, &XINT (return_rtx, i),
 				       name.string);
+#else
+	/* Handle some of the extra information that print_rtx
+	   can write out for these cases.  */
+	{
+	  /* print_rtx only writes out operand 5 for notes
+	     for NOTE_KIND values NOTE_INSN_DELETED_LABEL
+	     and NOTE_INSN_DELETED_DEBUG_LABEL.  */
+	  if (i == 5 && NOTE_P (return_rtx))
+	    break;
+
+	  if (i == 4 && INSN_P (return_rtx))
+	    {
+	      maybe_read_location (i, return_rtx);
+	      break;
+	    }
+
+	  read_name (&name);
+	  int value;
+	  if (format_ptr[i] == 'n')
+	    value = parse_note_insn_name (name.string);
+	  else
+	    value = atoi (name.string);
+	  XINT (return_rtx, i) = value;
+	}
+#endif
+	break;
+
+      case 'B':
+	{
+	  file_location loc = read_name_or_nil (&name);
+	  int bb_idx = atoi (name.string);
+	  if (bb_idx)
+	    rtx_reader_ptr->add_fixup_bb (loc, return_rtx, i, bb_idx);
+	}
 	break;
 
       case 'r':
@@ -1326,12 +1638,166 @@ read_rtx_code (const char *code_name)
 	validate_const_int (name.string);
 	set_regno_raw (return_rtx, atoi (name.string), 1);
 	REG_ATTRS (return_rtx) = NULL;
+#ifndef GENERATOR_FILE
+	{
+	  unsigned int regno = REGNO (return_rtx);
+	  ORIGINAL_REGNO (return_rtx) = regno;
+
+	  /* print_rtx can print a name for various registers
+	     after the register number.  Skip and discard it.  */
+	  if (regno < FIRST_PSEUDO_REGISTER
+	      || regno <= LAST_VIRTUAL_REGISTER)
+	    read_name (&name);
+
+	  /* Parse extra stuff at end of 'r'.
+	     We may have zero, one, or two sections marked by square
+	     brackets.  */
+	  int ch = read_skip_spaces ();
+	  bool expect_original_regno = false;
+	  if (ch == '[')
+	    {
+	      file_location loc = rtx_reader_ptr->get_current_location ();
+	      char *desc = read_until ("]", true);
+	      strip_trailing_whitespace (desc);
+	      const char *desc_start = desc;
+	      /* If ORIGINAL_REGNO (rtx) != regno, we will have:
+		 "orig:%i", ORIGINAL_REGNO (rtx).
+		 Consume it, we don't set ORIGINAL_REGNO, since we can
+		 get that from the 2nd copy later.  */
+	      if (0 == strncmp (desc, "orig:", 5))
+		{
+		  expect_original_regno = true;
+		  desc_start += 5;
+		  /* Skip to any whitespace following the integer.  */
+		  const char *space = strchr (desc_start, ' ');
+		  if (space)
+		    desc_start = space + 1;
+		}
+	      /* Any remaining text may be the REG_EXPR.  Alternatively we have
+		 no REG_ATTRS, and instead we have ORIGINAL_REGNO.  */
+	      if (ISDIGIT (*desc_start))
+		{
+		  /* Assume we have ORIGINAL_REGNO.  */
+		  ORIGINAL_REGNO (return_rtx) = atoi (desc_start);
+		}
+	      else
+		{
+		  /* Assume we have REG_EXPR.  */
+		  rtx_reader_ptr->add_fixup_expr (loc, return_rtx, desc_start);
+		}
+	      free (desc);
+	    }
+	  else
+	    unread_char (ch);
+	  if (expect_original_regno)
+	    {
+	      require_char_ws ('[');
+	      char *desc = read_until ("]", true);
+	      ORIGINAL_REGNO (return_rtx) = atoi (desc);
+	      free (desc);
+	    }
+	}
+#endif
 	break;
 
       default:
 	gcc_unreachable ();
       }
 
+#ifndef GENERATOR_FILE
+  /* Handle the various additional information that print-rtl.c can
+     write after the regular fields.  */
+  switch (GET_CODE (return_rtx))
+    {
+      case MEM:
+	{
+	  int ch;
+	  require_char_ws ('[');
+	  read_name (&name);
+	  MEM_ALIAS_SET (return_rtx) = atoi (name.string);
+	  /* We have either a MEM_EXPR, or a space.  */
+	  if (peek_char () != ' ')
+	    {
+	      file_location loc = rtx_reader_ptr->get_current_location ();
+	      char *desc = read_until (" +", false);
+	      rtx_reader_ptr->add_fixup_expr (loc, return_rtx, desc);
+	      free (desc);
+	    }
+	  else
+	    read_char ();
+
+	  /* We may optionally have '+' for MEM_OFFSET_KNOWN_P.  */
+	  ch = read_skip_spaces ();
+	  if (ch == '+')
+	    {
+	      read_name (&name);
+	      MEM_OFFSET_KNOWN_P (return_rtx) = 1;
+	      MEM_OFFSET (return_rtx) = atoi (name.string);
+	    }
+	  else
+	    unread_char (ch);
+
+	  /* Handle optional " S" for MEM_SIZE.  */
+	  ch = read_skip_spaces ();
+	  if (ch == 'S')
+	    {
+	      read_name (&name);
+	      MEM_SIZE (return_rtx) = atoi (name.string);
+	    }
+	  else
+	    unread_char (ch);
+
+	  /* Handle optional " A" for MEM_ALIGN.  */
+	  ch = read_skip_spaces ();
+	  if (ch == 'A' && peek_char () != 'S')
+	    {
+	      read_name (&name);
+	      MEM_ALIGN (return_rtx) = atoi (name.string);
+	    }
+
+	  /* Handle optional " AS" for MEM_ADDR_SPACE.  */
+	  ch = read_skip_spaces ();
+	  if (ch == 'A' && peek_char () == 'S')
+	    {
+	      read_char ();
+	      read_name (&name);
+	      MEM_ADDR_SPACE (return_rtx) = atoi (name.string);
+	    }
+	  else
+	    unread_char (ch);
+
+	  require_char (']');
+	}
+	break;
+
+      case CODE_LABEL:
+	{
+	  /* Parse LABEL_NUSES.  */
+	  require_char_ws ('[');
+	  read_name (&name);
+	  LABEL_NUSES (return_rtx) = atoi (name.string);
+	  require_word_ws ("uses");
+	  require_char_ws (']');
+	  /* TODO: parse LABEL_KIND.  */
+	  /* For now, skip until closing ')'.  */
+	  do
+	    {
+	      char ch = read_char ();
+	      if (ch == ')')
+		{
+		  unread_char (ch);
+		  break;
+		}
+	    }
+	  while (1);
+	}
+	break;
+
+      default:
+	break;
+    }
+#endif
+
   if (CONST_WIDE_INT_P (return_rtx))
     {
       read_name (&name);
@@ -1392,18 +1858,146 @@ read_rtx_code (const char *code_name)
   return return_rtx;
 }
 
+#ifndef GENERATOR_FILE
+
+/* Helper function for consolidate_reg.  */
+
+static rtx
+lookup_global_register (int regno)
+{
+  /* FIXME: do we need to check for Pmode? */
+  switch (regno)
+    {
+    case STACK_POINTER_REGNUM:
+      return stack_pointer_rtx;
+    case FRAME_POINTER_REGNUM:
+      return frame_pointer_rtx;
+    case HARD_FRAME_POINTER_REGNUM:
+      return hard_frame_pointer_rtx;
+    case ARG_POINTER_REGNUM:
+      return arg_pointer_rtx;
+    case VIRTUAL_INCOMING_ARGS_REGNUM:
+      return virtual_incoming_args_rtx;
+    case VIRTUAL_STACK_VARS_REGNUM:
+      return virtual_stack_vars_rtx;
+    case VIRTUAL_STACK_DYNAMIC_REGNUM:
+      return virtual_stack_dynamic_rtx;
+    case VIRTUAL_OUTGOING_ARGS_REGNUM:
+      return virtual_outgoing_args_rtx;
+    case VIRTUAL_CFA_REGNUM:
+      return virtual_cfa_rtx;
+    case VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM:
+      return virtual_preferred_stack_boundary_rtx;
+#ifdef return_ADDRESS_POINTER_REGNUM
+    case 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);
+
+  unsigned 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 = 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 = old_size * 2;
+    }
+  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 running in the RTL frontend, we must consolidate some
+   rtx so that we use singletons where singletons are expected
+   (e.g. we don't want multiple "(const_int 0 [0])" rtx, since
+   these are tested via pointer equality against const0_rtx.  */
+
+static rtx
+consolidate_singletons (rtx x)
+{
+  if (!x)
+    return x;
+
+ switch (GET_CODE (x))
+    {
+    /* FIXME: do we need to check for VOIDmode for these?  */
+    case PC: return pc_rtx;
+    case RETURN: return ret_rtx;
+    case SIMPLE_RETURN: return simple_return_rtx;
+    case CC0: return cc0_rtx;
+
+    case REG:
+      return consolidate_reg (x);
+
+    case CONST_INT:
+      {
+	if (INTVAL (x) == 0)
+	  return const0_rtx;
+      }
+      break;
+
+    default:
+      break;
+    }
+
+  return x;
+}
+
+#endif /* #ifndef GENERATOR_FILE */
+
+
 /* Read a nested rtx construct from the MD file and return it.  */
 
 static rtx
 read_nested_rtx (void)
 {
   struct md_name name;
-  int c;
   rtx return_rtx;
 
-  c = read_skip_spaces ();
-  if (c != '(')
-    fatal_expected_char ('(', c);
+  require_char_ws ('(');
 
   read_name (&name);
   if (strcmp (name.string, "nil") == 0)
@@ -1411,9 +2005,11 @@ read_nested_rtx (void)
   else
     return_rtx = read_rtx_code (name.string);
 
-  c = read_skip_spaces ();
-  if (c != ')')
-    fatal_expected_char (')', c);
+  require_char_ws (')');
+
+#ifndef GENERATOR_FILE
+  return_rtx = consolidate_singletons (return_rtx);
+#endif /* #ifndef GENERATOR_FILE */
 
   return return_rtx;
 }
diff --git a/gcc/rtl.c b/gcc/rtl.c
index a445cdc..9729c82 100644
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -878,3 +878,5 @@ rtl_check_failed_flag (const char *name, const_rtx r, const char *file,
      name, GET_RTX_NAME (GET_CODE (r)), func, trim_filename (file), line);
 }
 #endif /* ENABLE_RTL_FLAG_CHECKING */
+
+bool in_rtl_frontend_p = false;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index b531ab7..7b86e1a 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 bool in_rtl_frontend_p;
 
 #endif /* ! GCC_RTL_H */
diff --git a/gcc/rtl/Make-lang.in b/gcc/rtl/Make-lang.in
new file mode 100644
index 0000000..8c913bc
--- /dev/null
+++ b/gcc/rtl/Make-lang.in
@@ -0,0 +1,148 @@
+# Make-lang.in -- Top level -*- makefile -*- fragment for RTL frontend.
+
+# Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This file is part of GCC.
+
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# This file provides the language dependent support in the main Makefile.
+
+# The name for selecting the RTL frontend in LANGUAGES.
+rtl: rtl1$(exeext)
+
+.PHONY: rtl
+
+# Use strict warnings.
+rtl-warn = $(STRICT_WARN)
+
+RTL_OBJS = \
+	rtl/rtl-errors.o \
+	rtl/rtl-frontend.o \
+	read-md.o \
+	read-rtl.o
+
+rtl1$(exeext): $(RTL_OBJS) attribs.o $(BACKEND) $(LIBDEPS)
+	+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+	      $(RTL_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS)
+
+# Build hooks:
+
+rtl.all.cross:
+rtl.start.encap:
+rtl.rest.encap:
+rtl.info:
+rtl.man:
+
+lang_checks += check-rtl
+lang_checks_parallelized += check-rtl
+check_rtl_parallelize = 10
+
+# Install hooks.
+
+rtl.install-common: installdirs
+	-rm -f $(DESTDIR)$(bindir)/$(GCCRTL_INSTALL_NAME)$(exeext)
+	$(INSTALL_PROGRAM) gccrtl$(exeext) $(DESTDIR)$(bindir)/$(GCCRTL_INSTALL_NAME)$(exeext)
+	-if test -f rtl1$(exeext); then \
+	  if test -f gccrtl-cross$(exeext); then \
+	    :; \
+	  else \
+	    rm -f $(DESTDIR)$(bindir)/$(GCCRTL_TARGET_INSTALL_NAME)$(exeext); \
+	    ( cd $(DESTDIR)$(bindir) && \
+	      $(LN) $(GCCRTL_INSTALL_NAME)$(exeext) $(GCCRTL_TARGET_INSTALL_NAME)$(exeext) ); \
+	  fi; \
+	fi
+
+rtl.install-plugin:
+
+rtl.install-info: $(DESTDIR)$(infodir)/gccrtl.info
+
+rtl.install-pdf: doc/gccrtl.pdf
+	@$(NORMAL_INSTALL)
+	test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
+	@for p in doc/gccrtl.pdf; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  f=$(pdf__strip_dir) \
+	  echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
+	  $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
+	done
+
+rtl.install-html: $(build_htmldir)/rtl
+	@$(NORMAL_INSTALL)
+	test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)"
+	@for p in $(build_htmldir)/rtl; do \
+	  if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \
+	  f=$(html__strip_dir) \
+	  if test -d "$$d$$p"; then \
+	    echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \
+	    $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
+	    echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
+	    $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
+	  else \
+	    echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
+	    $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
+	  fi; \
+	done
+
+rtl.install-man: $(DESTDIR)$(man1dir)/$(GCCRTL_INSTALL_NAME)$(man1ext)
+
+$(DESTDIR)$(man1dir)/$(GCCRTL_INSTALL_NAME)$(man1ext): doc/gccrtl.1 installdirs
+	-rm -f $@
+	-$(INSTALL_DATA) $< $@
+	-chmod a-x $@
+
+rtl.uninstall:
+	rm -rf $(DESTDIR)$(bindir)/$(GCCRTL_INSTALL_NAME)$(exeext)
+	rm -rf $(DESTDIR)$(man1dir)/$(GCCRTL_INSTALL_NAME)$(man1ext)
+	rm -rf $(DESTDIR)$(bindir)/$(GCCRTL_TARGET_INSTALL_NAME)$(exeext)
+	rm -rf $(DESTDIR)$(infodir)/gccrtl.info*
+
+# Clean hooks.
+
+rtl.mostlyclean:
+	-rm -f rtl/*$(objext)
+	-rm -f rtl/*$(coverageexts)
+	-rm -f gccrtl$(exeext) gccrtl-cross$(exeext) rtl1$(exeext)
+rtl.clean:
+rtl.distclean:
+rtl.maintainer-clean:
+	-rm -f $(docobjdir)/gccrtl.1
+
+# Stage hooks.
+
+rtl.stage1: stage1-start
+	-mv rtl/*$(objext) stage1/rtl
+rtl.stage2: stage2-start
+	-mv rtl/*$(objext) stage2/rtl
+rtl.stage3: stage3-start
+	-mv rtl/*$(objext) stage3/rtl
+rtl.stage4: stage4-start
+	-mv rtl/*$(objext) stage4/rtl
+rtl.stageprofile: stageprofile-start
+	-mv rtl/*$(objext) stageprofile/rtl
+rtl.stagefeedback: stagefeedback-start
+	-mv rtl/*$(objext) stagefeedback/rtl
+
+CFLAGS-rtl/rtl-lang.o += -DDEFAULT_TARGET_VERSION=\"$(version)\" \
+	-DDEFAULT_TARGET_MACHINE=\"$(target_noncanonical)\"
+
+RTLINCLUDES = -I $(srcdir)/rtl -I $(srcdir)/rtl/rtlfrontend
+
+CFLAGS-rtl/rtl-gcc.o += $(RTLINCLUDES)
+CFLAGS-rtl/rtl-linemap.o += $(RTLINCLUDES)
+
+rtl/%.o: rtl/rtlfrontend/%.c
+	$(COMPILE) $(RTLINCLUDES) $<
+	$(POSTCOMPILE)
diff --git a/gcc/rtl/config-lang.in b/gcc/rtl/config-lang.in
new file mode 100644
index 0000000..3b101ce
--- /dev/null
+++ b/gcc/rtl/config-lang.in
@@ -0,0 +1,36 @@
+# config-lang.in -- Top level configure fragment for RTL frontend.
+
+# Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This file is part of GCC.
+
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language	- name of language as it would appear in $(LANGUAGES)
+# compilers	- value to add to $(COMPILERS)
+
+language="rtl"
+
+compilers="rtl1\$(exeext)"
+
+target_libs=""
+
+gtfiles="\$(srcdir)/rtl/rtl-frontend.c"
+
+# Do not build by default.
+build_by_default="no"
diff --git a/gcc/rtl/lang-specs.h b/gcc/rtl/lang-specs.h
new file mode 100644
index 0000000..2af33ab
--- /dev/null
+++ b/gcc/rtl/lang-specs.h
@@ -0,0 +1,25 @@
+/* lang-specs.h -- gcc driver specs for RTL frontend.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* This is the contribution to the `default_compilers' array in gcc.c
+   for the RTL frontend.  */
+
+{".rtl",  "@RTL", 0, 1, 0},
+{"@RTL",  "rtl1 %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}",
+    0, 1, 0},
diff --git a/gcc/rtl/lang.opt b/gcc/rtl/lang.opt
new file mode 100644
index 0000000..42adac0
--- /dev/null
+++ b/gcc/rtl/lang.opt
@@ -0,0 +1,38 @@
+; lang.opt -- Options for the gcc RTL front end.
+
+; Copyright (C) 2016 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 3, or (at your option) any later
+; version.
+; 
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+; for more details.
+; 
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3.  If not see
+; <http://www.gnu.org/licenses/>.
+
+; See the GCC internals manual for a description of this file's format.
+
+; Please try to keep this file in ASCII collating order.
+
+Language
+RTL
+
+froundtrip=
+RTL Joined RejectNegative
+After loading the RTL input file, immediately dump it to the given path,
+for sanity-checking the loader.
+
+fsingle-pass=
+RTL Joined RejectNegative
+After loading the RTL input file, run the specified pass on it.
+
+
+; This comment is to ensure we retain the blank line above.
diff --git a/gcc/rtl/notes.rst b/gcc/rtl/notes.rst
new file mode 100644
index 0000000..324edd3
--- /dev/null
+++ b/gcc/rtl/notes.rst
@@ -0,0 +1,201 @@
+RTL frontend
+============
+
+Purpose
+-------
+
+Historically GCC testing has been done by providing source files
+to be built with various command-line options (via DejaGnu
+directives), dumping state at pertinent places, and verifying
+properties of the state via these dumps.
+
+A strength of this approach is that we have excellent integration
+testing, as every test case exercises the toolchain as a whole, but
+it has the drawback that when testing a specific pass,
+we have little control of the input to that specific pass.  We
+provide input, and the various passes transform the state
+of the internal representation::
+
+  INPUT -> PASS-1 -> STATE-1 -> PASS-2 -> STATE-2 -> ...
+    -> etc ->
+    -> ... -> PASS-n-1 -> STATE-n-1 -> PASS-n -> STATE-n
+                          ^            ^         ^
+                          |            |         Output from the pass
+                          |            The pass we care about
+                          The actual input to the pass
+
+so the intervening passes before "PASS-n" could make changes to the
+IR that affect the input seen by our pass ("STATE-n-1" above).  This
+can break our test cases, sometimes in a form that's visible,
+sometimes invisibly (e.g. where a test case silently stops providing
+coverage).
+
+The aim of the RTL frontend is to provide a convenient way to test
+individual passes in the backend, by loading dumps of specific RTL
+state (possibly edited by hand), and then running just one specific
+pass on them, so that we effectively have this::
+
+  INPUT -> PASS-n -> OUTPUT
+
+thus fixing the problem above.
+
+My hope is that this makes it easy to write more fine-grained and
+robust test coverage for the RTL phase of GCC.  However I see this
+as *complementary* to the existing "integrated testing" approach:
+patches should include both RTL frontend tests *and* integrated tests,
+to avoid regressing the great integration testing we currently have.
+
+The idea is to use the existing dump format as a input format, since
+presumably existing GCC developers are very familiar with the dump
+format.
+
+One other potential benefit of this approach is to allow unit-testing
+of machine descriptions - we could provide specific RTL fragments,
+and have the rtl.dg testsuite directly verify that we recognize all
+instructions and addressing modes that a given target ought to support.
+
+Structure
+---------
+
+The RTL frontend is similar to a regular frontend: a ``gcc/rtl``
+subdirectory within the source tree contains frontend-specific hooks.
+These provide a new ``rtl`` frontend, which can be optionally
+enabled at configuration time within ``--enable-languages``.
+
+If enabled, it builds an ``rtl1`` binary, which is invoked by the
+``gcc`` driver on files with a ``.rtl`` extension.
+
+The testsuite is below ``gcc/testsuite/rtl.dg``.  There's also
+a ``roundtrip`` subdirectory below this, in which every ``.rtl``
+file is loaded and then dumped; ``roundtrip.exp`` verifies that
+the dump is identical to the original file, thus ensuring that
+the RTL loaders faithfully rebuild the input dump.
+
+Limitations
+-----------
+
+* It's a work-in-progress.  There will be bugs.
+
+* The existing RTL code is structured around a single function being
+  optimized, so, as a simplification, the RTL frontend can only handle
+  one function per input file.  Also, the dump format currently uses
+  comments to separate functions::
+
+    ;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+    ... various pass-specific things, sometimes expressed as comments,
+    sometimes not
+
+    ;;
+    ;; Full RTL generated for this function:
+    ;;
+    (note 1 0 6 NOTE_INSN_DELETED)
+    ;; etc, insns for function "test_1" go here
+    (insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+         (nil))
+
+    ;; Function test_2 (test_2, funcdef_no=1, decl_uid=1765, cgraph_uid=1, symbol_order=1)
+    ... various pass-specific things, sometimes expressed as comments,
+    sometimes not
+    ;;
+    ;; Full RTL generated for this function:
+    ;;
+    (note 1 0 5 NOTE_INSN_DELETED)
+    ;; etc, insns for function "test_2" go here
+    (insn 59 58 0 8 (use (reg/i:SF 21 xmm0)) ../../src/gcc/testsuite/rtl.dg/test.c:31 -1
+         (nil))
+
+  so that there's no clear separation of the instructions between the
+  two functions (and no metadata e.g. function names).
+
+  This could be fixed by adding a new clause to the dump e.g.::
+
+    (function "test_1" [
+      (note 1 0 6 NOTE_INSN_DELETED)
+      ;; etc, insns for function "test_1" go here
+      (insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+           (nil))
+      ])
+
+    (function "test_2" [
+      (note 1 0 5 NOTE_INSN_DELETED)
+      ;; etc, insns for function "test_2" go here
+      (insn 59 58 0 8 (use (reg/i:SF 21 xmm0)) ../../src/gcc/testsuite/rtl.dg/test.c:31 -1
+           (nil))
+      ])
+
+  or somesuch (this wouldn't be an rtx code, just something in rtl-frontend.c).
+  The RTL frontend could then compile each function in turn after parsing each
+  one (probably the easiest way to deal with the global state in the RTL parts
+  of the compiler).
+
+* The RTL frontend doesn't have any knowledge of the name of the function,
+  of parameters, types, locals, globals, etc.  It creates a single function.
+  The function is currently hardcoded to have this signature:
+
+     int test_1 (int, int, int);
+
+  since there's no syntax for specify otherwise, and we need to provide
+  a ``FUNCTION_DECL`` tree when building a function object (by calling
+  ``allocate_struct_function``).
+
+* Similarly, there are no types beyond the built-in ones; all expressions
+  are treated as being of type ``int``.  I suspect that this approach
+  will be too simplistic when it comes to e.g. aliasing.
+
+* There's no support for running more than one pass; fixing this would
+  require being able to run passes from a certain point onwards.
+
+* Roundtripping of recognized instructions may be an issue (i.e. those
+  with ``INSN_CODE`` != -1), such as the ``667 {jump}`` in the following::
+
+    (jump_insn 50 49 51 10
+      (set (pc)
+           (label_ref:DI 59)) ../../src/test-switch.c:18 667 {jump}
+           (nil) -> 59)
+
+  since the integer ID can change when the .md files are changed
+  (and the associated pattern name is very much target-specific).
+  It may be best to reset them to -1 in the input files (and delete the
+  operation name), giving::
+
+    (jump_insn 50 49 51 10
+      (set (pc)
+           (label_ref:DI 59)) ../../src/test-switch.c:18 -1
+           (nil) -> 59)
+
+* Currently there's no explicit CFG edge information in the dumps.
+  The ``rtl1`` frontend reconstructs the edges based on jump instructions.
+  As I understand the `distinction between cfgrtl and cfglayout modes
+  https://gcc.gnu.org/wiki/cfglayout_mode`_ , this is OK for "cfgrtl" mode,
+  but isn't going to work for "cfglayout" mode - in the latter,
+  unconditional jumps are represented purely by edges in the CFG, and this
+  information isn't currently present in the dumps  (perhaps we could add it
+  if it's an issue).
+
+Open Questions
+--------------
+
+* Register numbering: consider this fragment of RTL emitted during
+  expansion::
+
+    (reg/f:DI 82 virtual-stack-vars)
+
+  At the time of emission, register 82 is the ``VIRTUAL_STACK_VARS_REGNUM``,
+  and this value is effectively hardcoded into the dump.  Presumably this
+  is baking in assumptions about the target into the test.  Also, how likely is
+  this value to change?  When we reload the dump, should we notice that this
+  is tagged with ``virtual-stack-vars`` and override the specific register
+  number to use the current value of ``VIRTUAL_STACK_VARS_REGNUM`` on the
+  target ``rtl1`` was built for?
+
+TODO items
+----------
+
+* test with other architectures
+
+* roundtrip.exp: strip out comments in source when comparing roundtrip
+
+* example with "-g"
+
+* implement a fuzzer (or use AFL on the existing test cases)
diff --git a/gcc/rtl/rtl-errors.c b/gcc/rtl/rtl-errors.c
new file mode 100644
index 0000000..0c6d4ab
--- /dev/null
+++ b/gcc/rtl/rtl-errors.c
@@ -0,0 +1,35 @@
+/* rtl-error.c - Replacement for errors.c for use by RTL frontend
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "errors.h"
+
+/* FIXME.  */
+
+void
+fatal (const char *, ...)
+{
+  // TODO
+  abort ();
+}
+
+int have_error;
+
diff --git a/gcc/rtl/rtl-frontend.c b/gcc/rtl/rtl-frontend.c
new file mode 100644
index 0000000..8ac22db3
--- /dev/null
+++ b/gcc/rtl/rtl-frontend.c
@@ -0,0 +1,1219 @@
+/* rtl-frontend.c - Top-level of RTL frontend
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tree.h"
+#include "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 "deferred-locations.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"
+
+/* Language-dependent contents of a type.  */
+
+struct GTY(()) lang_type
+{
+  char dummy;
+};
+
+/* Language-dependent contents of a decl.  */
+
+struct GTY(()) lang_decl
+{
+  char dummy;
+};
+
+/* Language-dependent contents of an identifier.  This must include a
+   tree_identifier.  */
+
+struct GTY(()) lang_identifier
+{
+  struct tree_identifier common;
+};
+
+/* The resulting tree type.  */
+
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+	   chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+  union tree_node GTY((tag ("0"),
+		       desc ("tree_node_structure (&%h)"))) generic;
+  struct lang_identifier GTY((tag ("1"))) identifier;
+};
+
+/* We don't use language_function.  */
+
+struct GTY(()) language_function
+{
+  int dummy;
+};
+
+/* Language hooks.  */
+
+/* Implementation of LANG_HOOKS_INIT for the RTL frontend.  */
+
+static bool
+rtl_langhook_init (void)
+{
+  in_rtl_frontend_p = true;
+
+  build_common_tree_nodes (false);
+
+  /* I don't know why this has to be done explicitly.  */
+  void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+  build_common_builtin_nodes ();
+
+  /* The default precision for floating point numbers.  This is used
+     for floating point constants with abstract type.  This may
+     eventually be controllable by a command line option.  */
+  mpfr_set_default_prec (256);
+
+  return true;
+}
+
+/* Implementation of LANG_HOOKS_OPTION_LANG_MASK for the RTL frontend.  */
+
+static unsigned int
+rtl_langhook_option_lang_mask (void)
+{
+  return CL_RTL;
+}
+
+/* The value of "-froundtrip=", if any.  */
+
+static const char *roundtrip_filename = NULL;
+
+/* The value of "-fsingle-pass=", if any.  */
+
+static const char *single_pass_name = NULL;
+
+/* Implementation of LANG_HOOKS_HANDLE_OPTION for the RTL frontend.  */
+
+static bool
+rtl_langhook_handle_option (
+    size_t scode,
+    const char *arg,
+    int value ATTRIBUTE_UNUSED,
+    int kind ATTRIBUTE_UNUSED,
+    location_t loc ATTRIBUTE_UNUSED,
+    const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+{
+  enum opt_code code = (enum opt_code) scode;
+
+  switch (code)
+    {
+    case OPT_froundtrip_:
+      roundtrip_filename = xstrdup (arg);
+      break;
+
+    case OPT_fsingle_pass_:
+      single_pass_name =  xstrdup (arg);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+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 INSN_LOCATION
+   of the insn based on a deferred_location *.  */
+
+class fixup_source_location : public operand_fixup
+{
+ public:
+  fixup_source_location (file_location loc, rtx insn,
+			 int operand_idx,
+			 deferred_location *dloc)
+    : operand_fixup (loc, insn, operand_idx),
+      m_dloc (dloc)
+  {}
+
+  void apply (function_reader *reader) const;
+
+ private:
+  deferred_location *m_dloc;
+};
+
+/* 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))
+  {}
+
+  void apply (function_reader *reader) const;
+
+ private:
+  const 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))
+  {}
+
+  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 ();
+
+  void handle_unknown_directive (file_location, const char *);
+
+  void add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+			   int insn_uid);
+
+  void add_fixup_bb (file_location loc, rtx insn,
+		     int operand_idx, int bb_idx);
+
+  void add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+					int operand_idx, int bb_idx);
+
+  void add_fixup_source_location (file_location loc, rtx insn,
+				  int operand_idx,
+				  const char *filename, int lineno);
+
+  void add_fixup_jump_label (file_location loc, rtx insn,
+			     int operand_idx,
+			     const char *label);
+
+  void add_fixup_expr (file_location loc, rtx x,
+		       const char *desc);
+
+  void create_function ();
+  void apply_fixups ();
+  void create_cfg_edges ();
+
+  rtx_insn **get_insn_by_uid (int uid);
+
+  rtx_insn *get_first_insn () const { return m_first_insn; }
+
+  tree parse_mem_expr (const char *desc);
+
+ private:
+  void create_cfg_and_basic_blocks ();
+
+ private:
+  struct uid_hash : int_hash <int, -1, -2> {};
+  hash_map<uid_hash, rtx_insn *> m_insns_by_uid;
+  auto_vec<fixup *> m_fixups;
+  bitmap_head m_bb_indices;
+  rtx_insn *m_first_insn;
+  deferred_locations m_deferred_locations;
+  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 INSN_LOCATION of the insn based on a deferred_location *.  */
+
+void
+fixup_source_location::apply (function_reader */*reader*/) const
+{
+  INSN_LOCATION (as_a <rtx_insn *> (m_rtx)) = m_dloc->m_srcloc;
+}
+
+/* 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 () : rtx_reader (),
+    m_first_insn (NULL)
+{
+  bitmap_initialize (&m_bb_indices, NULL);
+  bitmap_set_bit (&m_bb_indices, ENTRY_BLOCK);
+  bitmap_set_bit (&m_bb_indices, EXIT_BLOCK);
+}
+
+/* function_reader's destructor.  */
+
+function_reader::~function_reader ()
+{
+  int i;
+  fixup *f;
+  FOR_EACH_VEC_ELT (m_fixups, i, f)
+    delete f;
+}
+
+/* Implementation of rtx_reader::handle_unknown_directive.
+   Parse rtx instructions by calling read_rtx_code, calling
+   set_first_insn and set_last_insn as appropriate.  */
+
+void
+function_reader::handle_unknown_directive (file_location /*start_loc*/,
+					   const char *name)
+{
+  rtx x = read_rtx_code (name);
+  if (!x)
+    return;
+  rtx_insn *insn = as_a <rtx_insn *> (x);
+  set_last_insn (insn);
+  if (!m_first_insn)
+    {
+      m_first_insn = insn;
+      set_first_insn (insn);
+    }
+  m_insns_by_uid.put (INSN_UID (insn), insn);
+}
+
+/* Implementation of rtx_reader::add_fixup_insn_uid.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+				     int insn_uid)
+{
+  m_fixups.safe_push (new fixup_insn_uid (loc, insn, operand_idx, insn_uid));
+}
+
+/* Implementation of rtx_reader::add_fixup_bb.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_bb (file_location loc, rtx insn, int operand_idx,
+			       int bb_idx)
+{
+  bitmap_set_bit (&m_bb_indices, bb_idx);
+  m_fixups.safe_push (new fixup_bb (loc, insn, operand_idx, bb_idx));
+}
+
+/* Implementation of rtx_reader::add_fixup_note_insn_basic_block.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+						  int operand_idx, int bb_idx)
+{
+  m_fixups.safe_push (new fixup_note_insn_basic_block (loc, insn, operand_idx,
+						       bb_idx));
+}
+
+/* Implementation of rtx_reader::add_fixup_source_location.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_source_location (file_location loc, rtx insn,
+					    int operand_idx,
+					    const char *filename, int lineno)
+{
+  source_file *file = m_deferred_locations.get_source_file (filename);
+  source_line *line = file->get_source_line (lineno);
+  deferred_location *dloc = line->get_location (NULL, 0);
+  m_fixups.safe_push (new fixup_source_location (loc, insn, operand_idx, dloc));
+}
+
+/* Implementation of rtx_reader::add_fixup_jump_label.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_jump_label (file_location loc, rtx insn,
+				       int operand_idx,
+				       const char *label)
+{
+  m_fixups.safe_push (new fixup_jump_label (loc, insn, operand_idx, label));
+}
+
+/* Implementation of rtx_reader::add_fixup_expr.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_expr (file_location loc, rtx insn,
+				 const char *desc)
+{
+  gcc_assert (desc);
+  /* Fail early if the RTL reader erroneously hands us an int.  */
+  gcc_assert (!ISDIGIT (desc[0]));
+
+  m_fixups.safe_push (new fixup_expr (loc, insn, desc));
+}
+
+/* Set up state for the function *before* fixups are applied.
+
+   Create "cfun" and a decl for the function.
+   For the moment, every function decl is hardcoded as
+      int test_1 (int i, int j, int k);
+   Set up various other state:
+   - state set up by expand_function_start (e.g. crtl->return_rtx).
+   - the cfg and basic blocks (edges are created later, *after* fixups
+   are applied).
+   - add the function to the callgraph.  */
+
+void
+function_reader::create_function ()
+{
+  /* Currently we assume cfgrtl mode, rather than cfglayout mode.  */
+  if (0)
+    cfg_layout_rtl_register_cfg_hooks ();
+  else
+    rtl_register_cfg_hooks ();
+
+  /* Create cfun.  */
+  tree fn_name = get_identifier ("test_1");
+  tree int_type = integer_type_node;
+  tree return_type = int_type;
+  tree arg_types[3] = {int_type, int_type, int_type};
+  tree fn_type = build_function_type_array (return_type, 3, arg_types);
+  tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+				 fn_type);
+  tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+			     return_type);
+  DECL_ARTIFICIAL (resdecl) = 1;
+  DECL_IGNORED_P (resdecl) = 1;
+  DECL_RESULT (fndecl) = resdecl;
+  allocate_struct_function (fndecl, false);
+  /* This sets cfun.  */
+
+  /* Normally, various state gets set up by expand_function_start, e.g.
+     crtl->return_rtx, based on DECL_RESULT (fndecl).
+     We call it here to ensure the state is set up, with emit_insns as
+     false, so no new instructions are emitted.  */
+  current_function_decl = fndecl;
+  expand_function_start (fndecl, false);
+
+  create_cfg_and_basic_blocks ();
+  cfun->curr_properties = (PROP_cfg | PROP_rtl);
+
+  /* Do we need this to force cgraphunit.c to output the function? */
+  DECL_EXTERNAL (fndecl) = 0;
+  DECL_PRESERVE_P (fndecl) = 1;
+
+  /* Add to cgraph.  */
+  cgraph_node::add_new_function (fndecl, true /*lowered*/);
+
+  current_function_decl = NULL;
+}
+
+/* Apply all of the recorded fixups.  */
+
+void
+function_reader::apply_fixups ()
+{
+  m_deferred_locations.add_to_line_table ();
+  /* 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);
+
+  /* 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);
+	    }
+	}
+    }
+}
+
+/*  Locate and run PASS_NAME on cfun.  */
+
+static void
+run_one_pass_by_name (const char *pass_name)
+{
+  opt_pass *pass = g->get_passes ()->get_pass_by_name (pass_name);
+  if (!pass)
+    {
+      error_at (UNKNOWN_LOCATION, "unrecognized pass: %qs", pass_name);
+      return;
+    }
+
+  /* Forcibly create the dataflow instance.  We'll need to do this on passes
+     that normally occur after pass_df_initialize/pass_df_initialize_no_opt.  */
+  /* FIXME: better conditional logic here.  */
+  if (0 == strcmp (pass_name, "rtl-ira")
+      || 0 == strcmp (pass_name, "rtl-reload")
+      || 0 == strcmp (pass_name, "rtl-pro_and_epilogue"))
+    {
+      opt_pass *df_pass = g->get_passes ()->get_pass_by_name ("rtl-dfinit");
+      gcc_assert (df_pass);
+      current_function_decl = cfun->decl;
+      df_pass->execute (cfun);
+
+      /* The dataflow instance should now exist.  */
+      gcc_assert (df);
+
+      df_analyze ();
+    }
+
+  /* Ensure reg_renumber is set up.  */
+  resize_reg_info ();
+
+  max_regno = max_reg_num ();
+
+  /* Pass "reload" sets the global "reload_completed", and many things
+     depend on this (e.g. instructions in .md files).  */
+  /* FIXME: better conditional logic here.  */
+  if (0 == strcmp (pass_name, "rtl-final"))
+    reload_completed = 1;
+
+  /* The INSN_ADDRESSES vec is normally set up by shorten_branches; we must
+     manually set it up for passes that run after this.  */
+  /* FIXME: better conditional logic here.  */
+  if (0 == strcmp (pass_name, "rtl-final"))
+    INSN_ADDRESSES_ALLOC (get_max_uid ());
+
+  /* Run the user-specified pass.  */
+  bitmap_obstack_initialize (NULL);
+  bitmap_obstack_initialize (&reg_obstack);
+  pass_init_dump_file (pass);
+  current_function_decl = cfun->decl;
+  pass->execute (cfun);
+  current_function_decl = NULL;
+  if (dump_file)
+    print_rtl_with_bb (dump_file, get_insns (), dump_flags);
+  pass_fini_dump_file (pass);
+  bitmap_obstack_release (&reg_obstack);
+}
+
+/* Implementation of LANG_HOOKS_PARSE_FILE for the RTL frontend.  */
+
+static void
+rtl_langhook_parse_file (void)
+{
+  in_rtl_frontend_p = true;
+
+  initialize_rtl ();
+  init_emit ();
+  init_varasm_status ();
+
+  auto_vec<const char *> argv (num_in_fnames + 1);
+  argv.safe_push (progname);
+  for (unsigned i = 0; i < num_in_fnames; i++)
+    argv.safe_push (in_fnames[i]);
+  function_reader reader;
+  if (!reader.read_md_files (argv.length (), argv.address (), NULL))
+    return;
+
+  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 ();
+
+  /* If -froundtrip=FILENAME was provided, immediately dump the
+     result, so that the testsuite can compare it against the
+     input dump.  */
+  if (roundtrip_filename)
+    {
+      FILE *out = fopen (roundtrip_filename, "w");
+      if (out)
+	{
+	  print_rtl_with_bb (out, reader.get_first_insn (), 1024);
+	  fclose (out);
+	}
+      else
+	error_at (UNKNOWN_LOCATION, "unable to open %qs for -froundtrip",
+		  roundtrip_filename);
+    }
+
+/*  If -fsingle-pass=PASS_NAME was provided, locate and run PASS_NAME
+    on cfun, as created above.  */
+  if (single_pass_name)
+    run_one_pass_by_name (single_pass_name);
+}
+
+/* Implementation of LANG_HOOKS_TYPE_FOR_SIZE, taken from Go frontend.  */
+
+static tree
+rtl_langhook_type_for_size (unsigned int bits, int unsignedp)
+{
+  tree type;
+  if (unsignedp)
+    {
+      if (bits == INT_TYPE_SIZE)
+        type = unsigned_type_node;
+      else if (bits == CHAR_TYPE_SIZE)
+        type = unsigned_char_type_node;
+      else if (bits == SHORT_TYPE_SIZE)
+        type = short_unsigned_type_node;
+      else if (bits == LONG_TYPE_SIZE)
+        type = long_unsigned_type_node;
+      else if (bits == LONG_LONG_TYPE_SIZE)
+        type = long_long_unsigned_type_node;
+      else
+        type = make_unsigned_type(bits);
+    }
+  else
+    {
+      if (bits == INT_TYPE_SIZE)
+        type = integer_type_node;
+      else if (bits == CHAR_TYPE_SIZE)
+        type = signed_char_type_node;
+      else if (bits == SHORT_TYPE_SIZE)
+        type = short_integer_type_node;
+      else if (bits == LONG_TYPE_SIZE)
+        type = long_integer_type_node;
+      else if (bits == LONG_LONG_TYPE_SIZE)
+        type = long_long_integer_type_node;
+      else
+        type = make_signed_type(bits);
+    }
+  return type;
+}
+
+/* Implementation of LANG_HOOKS_TYPE_FOR_MODE, taken from Go frontend.  */
+
+static tree
+rtl_langhook_type_for_mode (machine_mode mode, int unsignedp)
+{
+  tree type;
+  /* Go has no vector types.  Build them here.  FIXME: It does not
+     make sense for the middle-end to ask the frontend for a type
+     which the frontend does not support.  However, at least for now
+     it is required.  See PR 46805.  */
+  if (VECTOR_MODE_P (mode))
+    {
+      tree inner;
+
+      inner = rtl_langhook_type_for_mode (GET_MODE_INNER (mode), unsignedp);
+      if (inner != NULL_TREE)
+	return build_vector_type_for_mode (inner, mode);
+      return NULL_TREE;
+    }
+
+  // FIXME: This static_cast should be in machmode.h.
+  enum mode_class mc = static_cast<enum mode_class>(GET_MODE_CLASS(mode));
+  if (mc == MODE_INT)
+    return rtl_langhook_type_for_size(GET_MODE_BITSIZE(mode), unsignedp);
+  else if (mc == MODE_FLOAT)
+    {
+      switch (GET_MODE_BITSIZE (mode))
+	{
+	case 32:
+	  return float_type_node;
+	case 64:
+	  return double_type_node;
+	default:
+	  // We have to check for long double in order to support
+	  // i386 excess precision.
+	  if (mode == TYPE_MODE(long_double_type_node))
+	    return long_double_type_node;
+	}
+    }
+  else if (mc == MODE_COMPLEX_FLOAT)
+    {
+      switch (GET_MODE_BITSIZE (mode))
+	{
+	case 64:
+	  return complex_float_type_node;
+	case 128:
+	  return complex_double_type_node;
+	default:
+	  // We have to check for long double in order to support
+	  // i386 excess precision.
+	  if (mode == TYPE_MODE(complex_long_double_type_node))
+	    return complex_long_double_type_node;
+	}
+    }
+
+#if HOST_BITS_PER_WIDE_INT >= 64
+  /* The middle-end and some backends rely on TImode being supported
+     for 64-bit HWI.  */
+  if (mode == TImode)
+    {
+      type = build_nonstandard_integer_type (GET_MODE_BITSIZE (TImode),
+					     unsignedp);
+      if (type && TYPE_MODE (type) == TImode)
+	return type;
+    }
+#endif
+  return NULL_TREE;
+}
+
+/* Implementation of LANG_HOOKS_BUILTIN_FUNCTION.  */
+
+static tree
+rtl_langhook_builtin_function (tree decl)
+{
+  return decl;
+}
+
+/* Implementation of LANG_HOOKS_GLOBAL_BINDINGS_P.
+   Return true if we are in the global binding level.  */
+
+static bool
+rtl_langhook_global_bindings_p (void)
+{
+  return current_function_decl == NULL_TREE;
+}
+
+/* Implementation of LANG_HOOKS_PUSHDECL.  */
+
+static tree
+rtl_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+/* Implementation of LANG_HOOKS_GETDECLS.  */
+
+static tree
+rtl_langhook_getdecls (void)
+{
+  return NULL;
+}
+
+/* Functions called directly by the generic backend.  */
+
+/* Implementation of "convert" taken from the Go frontend.  */
+
+tree
+convert (tree type, tree expr)
+{
+  if (type == error_mark_node
+      || expr == error_mark_node
+      || TREE_TYPE (expr) == error_mark_node)
+    return error_mark_node;
+
+  if (type == TREE_TYPE (expr))
+    return expr;
+
+  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
+    return fold_convert (type, expr);
+
+  switch (TREE_CODE (type))
+    {
+    case VOID_TYPE:
+    case BOOLEAN_TYPE:
+      return fold_convert (type, expr);
+    case INTEGER_TYPE:
+      return fold (convert_to_integer (type, expr));
+    case POINTER_TYPE:
+      return fold (convert_to_pointer (type, expr));
+    case REAL_TYPE:
+      return fold (convert_to_real (type, expr));
+    case COMPLEX_TYPE:
+      return fold (convert_to_complex (type, expr));
+    default:
+      break;
+    }
+
+  gcc_unreachable ();
+}
+
+#undef LANG_HOOKS_NAME
+#undef LANG_HOOKS_INIT
+#undef LANG_HOOKS_OPTION_LANG_MASK
+#undef LANG_HOOKS_HANDLE_OPTION
+#undef LANG_HOOKS_PARSE_FILE
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#undef LANG_HOOKS_PUSHDECL
+#undef LANG_HOOKS_GETDECLS
+
+#define LANG_HOOKS_NAME			"GCC RTL frontend"
+#define LANG_HOOKS_INIT			rtl_langhook_init
+#define LANG_HOOKS_OPTION_LANG_MASK	rtl_langhook_option_lang_mask
+#define LANG_HOOKS_HANDLE_OPTION	rtl_langhook_handle_option
+#define LANG_HOOKS_PARSE_FILE		rtl_langhook_parse_file
+#define LANG_HOOKS_TYPE_FOR_MODE	rtl_langhook_type_for_mode
+#define LANG_HOOKS_TYPE_FOR_SIZE	rtl_langhook_type_for_size
+#define LANG_HOOKS_BUILTIN_FUNCTION	rtl_langhook_builtin_function
+#define LANG_HOOKS_GLOBAL_BINDINGS_P	rtl_langhook_global_bindings_p
+#define LANG_HOOKS_PUSHDECL		rtl_langhook_pushdecl
+#define LANG_HOOKS_GETDECLS		rtl_langhook_getdecls
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-rtl-rtl-frontend.h"
+#include "gtype-rtl.h"
diff --git a/gcc/testsuite/lib/rtl-dg.exp b/gcc/testsuite/lib/rtl-dg.exp
new file mode 100644
index 0000000..8aa5943
--- /dev/null
+++ b/gcc/testsuite/lib/rtl-dg.exp
@@ -0,0 +1,64 @@
+#   Copyright (C) 1997, 1999, 2000, 2003, 2007 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Define rtl callbacks for dg.exp.
+
+# Load support procs.
+load_lib gcc-defs.exp
+
+proc rtl_target_compile { source dest type options } {
+    set result [target_compile $source $dest $type $options]
+    return $result
+}
+
+load_lib gcc-dg.exp
+
+proc rtl-dg-test { prog do_what extra_tool_flags } {
+    verbose "rtl-dg-test (rtl-dg.exp):" 3
+    verbose "  prog: $prog" 3
+    verbose "  do_what: $do_what" 3
+    verbose "  extra_tool_flags: $extra_tool_flags" 3
+
+    return [gcc-dg-test-1 rtl_target_compile $prog $do_what $extra_tool_flags]
+}
+
+
+proc rtl-dg-prune { system text } {
+    return [gcc-dg-prune $system $text]
+}
+
+# Modified dg-runtest that runs tests in both C++98 and C++11 modes
+# unless they specifically specify one or the other.
+proc rtl-dg-runtest { testcases default-extra-flags } {
+    global runtests
+
+    foreach test $testcases {
+	# look if this is dg-do-run test, in which case
+	# we cycle through the option list, otherwise we don't
+	if [expr [search_for $test "dg-do run"]] {
+	    set option_list $TORTURE_OPTIONS
+	} else {
+	    set option_list [list { -O } ]
+	}
+
+	set nshort [file tail [file dirname $test]]/[file tail $test]
+
+	foreach flags $option_list {
+	    verbose "Testing $nshort, $flags" 1
+	    dg-test $test $flags ${default-extra-flags}
+	}
+    }
+}
diff --git a/gcc/testsuite/rtl.dg/dfinit.rtl b/gcc/testsuite/rtl.dg/dfinit.rtl
new file mode 100644
index 0000000..cdde054
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/dfinit.rtl
@@ -0,0 +1,90 @@
+/* { dg-options "-fsingle-pass=rtl-dfinit -fdump-rtl-dfinit" } */
+
+/* Lightly-modified dump of test.c.247r.split1.  */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 3 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 29 3 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 29 13 30 3 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 30 29 16)
+(code_label 16 30 17 4 2 (nil) [1 uses])
+(note 17 16 18 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 4 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 5 3 (nil) [1 uses])
+(note 21 20 22 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 5 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 5 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 5 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+
+
+/* Verify that the dataflow information matches what cc1 would have
+   generated.  In particular, in earlier versions of the RTL
+   frontend, the exit block use of reg 0 (ax) wasn't picked up
+   on, due to not setting up crtl->return_rtx based on
+   DECL_RESULT (fndecl).  */
+/* { dg-final { scan-rtl-dump ";;  exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+/* { dg-final { scan-rtl-dump ";;  regs ever live.*0 .ax. 1 .dx. 4 .si. 5 .di. 17 .flags." "dfinit" } } */
diff --git a/gcc/testsuite/rtl.dg/final.rtl b/gcc/testsuite/rtl.dg/final.rtl
new file mode 100644
index 0000000..0dc1a85
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/final.rtl
@@ -0,0 +1,51 @@
+/* { dg-options "-fsingle-pass=rtl-final -fdump-rtl-final" } */
+
+/* Lightly-modified dump of test.c.289r.dwarf2. */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 32 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(note 32 6 5 2 NOTE_INSN_PROLOGUE_END)
+(note 5 32 31 2 NOTE_INSN_FUNCTION_BEG)
+(insn:TI 31 5 27 2 (set (reg:SI 0 ax [93])
+        (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+            (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 27 31 28 2 (parallel [
+            (set (reg:SI 1 dx [92])
+                (neg:SI (reg/v:SI 1 dx [orig:90 k ] [90])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_UNUSED (reg:CC 17 flags)
+        (nil)))
+(insn 28 27 29 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg/v:SI 5 di [orig:88 i ] [88])
+            (reg/v:SI 4 si [orig:89 j ] [89]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_DEAD (reg/v:SI 5 di [orig:88 i ] [88])
+        (expr_list:REG_DEAD (reg/v:SI 4 si [orig:89 j ] [89])
+            (nil))))
+(insn:TI 29 28 23 2 (set (reg:SI 0 ax [orig:87 <retval> ] [87])
+        (if_then_else:SI (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (reg:SI 1 dx [92])
+            (reg:SI 0 ax [93]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_DEAD (reg:CCGC 17 flags)
+        (expr_list:REG_DEAD (reg:SI 1 dx [92])
+            (nil))))
+(insn 23 29 34 2 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(jump_insn:TI 34 23 33 2 (simple_return) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil)
+ -> simple_return)
+(barrier 33 34 30)
+(note 30 33 0 (nil) NOTE_INSN_DELETED)
+
+/* Verify that asm was emitted.  */
+/* { dg-final { scan-assembler "test_1:" } } */
+/* { dg-final { scan-assembler ".cfi_startproc" } } */
+/* { dg-final { scan-assembler ".cfi_endproc" } } */
+
+/* Verify that the "simple_return" was recognized.
+   FIXME: this assumes i386.md.  */
+/* { dg-final { scan-assembler "ret" } } */
diff --git a/gcc/testsuite/rtl.dg/good-include.rtl b/gcc/testsuite/rtl.dg/good-include.rtl
new file mode 100644
index 0000000..24be829
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/good-include.rtl
@@ -0,0 +1,6 @@
+/* Verify that we can include fragments from another dump.
+   We give the included file a .md suffix to avoid it being
+   run by rtl.exp.  */
+
+(include "good-includee.md")
+/* TODO: verify that we have the instruction from the above file.  */
diff --git a/gcc/testsuite/rtl.dg/good-includee.md b/gcc/testsuite/rtl.dg/good-includee.md
new file mode 100644
index 0000000..e63997f
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/good-includee.md
@@ -0,0 +1 @@
+(note 1 0 0 (nil) NOTE_INSN_DELETED)
diff --git a/gcc/testsuite/rtl.dg/into-cfglayout.rtl b/gcc/testsuite/rtl.dg/into-cfglayout.rtl
new file mode 100644
index 0000000..87c3c67
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/into-cfglayout.rtl
@@ -0,0 +1,85 @@
+/* { dg-options "-fsingle-pass=rtl-into_cfglayout -fdump-rtl-into_cfglayout" } */
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 4 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 14 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 14 13 15 4 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 15 14 16)
+(code_label 16 15 17 5 2 (nil) [1 uses])
+(note 17 16 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 5 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 5 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 6 3 (nil) [1 uses])
+(note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 6 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 6 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+
+/* The conversion to cfglayout should eliminate unconditional jump
+   instructions...  */
+/* { dg-final { scan-rtl-dump "Removing jump 14." "into_cfglayout" } }  */
+/* { dg-final { scan-rtl-dump-not "jump_insn 14" "into_cfglayout" } }  */
+/* { dg-final { scan-rtl-dump-not "barrier 15" "into_cfglayout" } }  */
+
+/* ...but conditional jumps should be preserved.  */
+/* { dg-final { scan-rtl-dump "jump_insn 10" "into_cfglayout" } }  */
diff --git a/gcc/testsuite/rtl.dg/ira.rtl b/gcc/testsuite/rtl.dg/ira.rtl
new file mode 100644
index 0000000..6f2e438
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/ira.rtl
@@ -0,0 +1,84 @@
+/* { dg-options "-fsingle-pass=rtl-ira -fdump-rtl-ira" } */
+
+/* Lightly-modified dump of test.c.251r.asmcons.  */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 3 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 29 3 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 29 13 30 3 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 30 29 16)
+(code_label 16 30 17 4 2 (nil) [1 uses])
+(note 17 16 18 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 4 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 5 3 (nil) [1 uses])
+(note 21 20 22 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 5 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 5 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 5 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+
+/* Verify that IRA was run.  */
+/* { dg-final { scan-rtl-dump "Building IRA IR" "ira" } } */
diff --git a/gcc/testsuite/rtl.dg/missing-include.rtl b/gcc/testsuite/rtl.dg/missing-include.rtl
new file mode 100644
index 0000000..f99f3ef
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/missing-include.rtl
@@ -0,0 +1 @@
+(include "does-not-exist.rtl") /* { dg-error "include file .does-not-exist.rtl. not found" } */
diff --git a/gcc/testsuite/rtl.dg/pro_and_epilogue.rtl b/gcc/testsuite/rtl.dg/pro_and_epilogue.rtl
new file mode 100644
index 0000000..a63f908
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/pro_and_epilogue.rtl
@@ -0,0 +1,38 @@
+/* { dg-options "-fsingle-pass=rtl-pro_and_epilogue -fdump-rtl-pro_and_epilogue" } */
+
+/* Lightly-modified dump of test.c.259r.split2.  */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 5 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(note 5 6 31 2 NOTE_INSN_FUNCTION_BEG)
+(insn 31 5 27 2 (set (reg:SI 0 ax [93])
+        (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+            (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 27 31 28 2 (parallel [
+            (set (reg:SI 1 dx [92])
+                (neg:SI (reg/v:SI 1 dx [orig:90 k ] [90])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 28 27 29 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg/v:SI 5 di [orig:88 i ] [88])
+            (reg/v:SI 4 si [orig:89 j ] [89]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 29 28 23 2 (set (reg:SI 0 ax [orig:87 <retval> ] [87])
+        (if_then_else:SI (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (reg:SI 1 dx [92])
+            (reg:SI 0 ax [93]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 23 29 30 2 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(note 30 23 0 (nil) NOTE_INSN_DELETED)
+
+/* Verify that the prologue and epilogue were added.  */
+/* { dg-final { scan-rtl-dump-times "NOTE_INSN_PROLOGUE_END" 1 "pro_and_epilogue" } }  */
+
+/* We expect a jump_insn to "simple_return".  */
+/* { dg-final { scan-rtl-dump-times "simple_return" 2 "pro_and_epilogue" } }  */
+
diff --git a/gcc/testsuite/rtl.dg/roundtrip/code-labels.rtl b/gcc/testsuite/rtl.dg/roundtrip/code-labels.rtl
new file mode 100644
index 0000000..7c7fa4a
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/code-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/rtl.dg/roundtrip/frame-pointer.rtl b/gcc/testsuite/rtl.dg/roundtrip/frame-pointer.rtl
new file mode 100644
index 0000000..50e9e88
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/frame-pointer.rtl
@@ -0,0 +1,4 @@
+(insn 1 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 ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
diff --git a/gcc/testsuite/rtl.dg/roundtrip/insn-with-mode.rtl b/gcc/testsuite/rtl.dg/roundtrip/insn-with-mode.rtl
new file mode 100644
index 0000000..1dd4c92
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/insn-with-mode.rtl
@@ -0,0 +1,4 @@
+(insn:TI 31 0 0 2 (set (reg:SI 0 ax [93])
+        (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+            (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
diff --git a/gcc/testsuite/rtl.dg/roundtrip/jump-to-label.rtl b/gcc/testsuite/rtl.dg/roundtrip/jump-to-label.rtl
new file mode 100644
index 0000000..0ecd62a
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/jump-to-label.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/rtl.dg/roundtrip/jump-to-return.rtl b/gcc/testsuite/rtl.dg/roundtrip/jump-to-return.rtl
new file mode 100644
index 0000000..d7802da
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/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/rtl.dg/roundtrip/jump-to-simple-return.rtl b/gcc/testsuite/rtl.dg/roundtrip/jump-to-simple-return.rtl
new file mode 100644
index 0000000..541dd4b
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/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/rtl.dg/roundtrip/note-insn-basic-block.rtl b/gcc/testsuite/rtl.dg/roundtrip/note-insn-basic-block.rtl
new file mode 100644
index 0000000..8e535a1
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/note-insn-basic-block.rtl
@@ -0,0 +1 @@
+(note 1 0 0 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
diff --git a/gcc/testsuite/rtl.dg/roundtrip/note-insn-deleted.rtl b/gcc/testsuite/rtl.dg/roundtrip/note-insn-deleted.rtl
new file mode 100644
index 0000000..e63997f
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/note-insn-deleted.rtl
@@ -0,0 +1 @@
+(note 1 0 0 (nil) NOTE_INSN_DELETED)
diff --git a/gcc/testsuite/rtl.dg/roundtrip/reg-with-orig-regno.rtl b/gcc/testsuite/rtl.dg/roundtrip/reg-with-orig-regno.rtl
new file mode 100644
index 0000000..f75d984
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/reg-with-orig-regno.rtl
@@ -0,0 +1,4 @@
+(insn 31 0 0 2 (set (reg:SI 0 ax [93])
+        (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+            (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
diff --git a/gcc/testsuite/rtl.dg/roundtrip/roundtrip.exp b/gcc/testsuite/rtl.dg/roundtrip/roundtrip.exp
new file mode 100644
index 0000000..fbc7963
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/roundtrip.exp
@@ -0,0 +1,99 @@
+# Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Verify that all of the .rtl files in this directory
+# "round trip" i.e. that loading and then dumping them leads to
+# identical content.
+
+load_lib rtl-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_RTLFLAGS
+if ![info exists DEFAULT_RTLFLAGS] then {
+    set DEFAULT_RTLFLAGS ""
+    # -fdump-tree-rtl-raw
+}
+
+# Compare INPUT_FILE and OUTPUT_FILE, and issue pass/fail
+# results if they have equal/non-equal content.
+
+proc verify-roundtrip { input_file output_file } {
+    verbose "verify-roundtrip:" 3
+    verbose "  input_file: $input_file" 3
+    verbose "  output_file: $output_file" 3
+    # Use "diff" from DejaGnu's utils.exp
+    set diff_result [diff $input_file $output_file]
+    if { $diff_result == 1 } then {
+	pass "$input_file and $output_file are identical"
+    } else {
+	if { $diff_result == -1 } then {
+	    fail "$input_file and $output_file are non-identical"
+	} else {
+	    fail "problem comparing $input_file with $output_file"
+	}
+    }
+}
+
+# Override the default implementation of rtl-dg-test:
+
+rename rtl-dg-test saved-rtl-dg-test
+
+# Alternate implementation of rtl-dg-test which adds a -froundtrip=
+# argument, and verifies that the output is identical to the input.
+
+proc rtl-dg-test { prog do_what extra_tool_flags } {
+    verbose "rtl-dg-test (roundtrip.exp):" 3
+    verbose "  prog: $prog" 3
+    verbose "  do_what: $do_what" 3
+    verbose "  extra_tool_flags: $extra_tool_flags" 3
+
+    # Generate an output filename by stripping off the path from
+    # $prog, and adding a ".roundtrip.rtl" suffix.
+    set output_file [file tail $prog]
+    set output_file "$output_file.roundtrip.rtl"
+
+    # Use it with -froundtrip=.
+    set options \
+	"$extra_tool_flags -froundtrip=$output_file"
+    verbose "options=$options" 3
+
+    set result [gcc-dg-test-1 rtl_target_compile $prog $do_what $options]
+
+    # Verify that the output file is identical to the input file.
+    verify-roundtrip $prog $output_file
+    remote_file build delete $output_file
+    return $result
+}
+
+
+# Initialize `dg'.
+dg-init
+
+# Gather a list of all tests, with the exception of those in directories
+# that are handled specially.
+set tests [lsort [find $srcdir/$subdir *.rtl]]
+
+verbose "roundtrip.exp tests: $tests" 1
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_RTLFLAGS
+
+# Restore the default implementation of rtl-dg-test:
+rename rtl-dg-test ""
+rename saved-rtl-dg-test rtl-dg-test
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/rtl.dg/roundtrip/test-loop.cleaned.rtl b/gcc/testsuite/rtl.dg/roundtrip/test-loop.cleaned.rtl
new file mode 100644
index 0000000..c2930b9
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/test-loop.cleaned.rtl
@@ -0,0 +1,75 @@
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 4 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 14 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 14 13 15 4 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 15 14 16)
+(code_label 16 15 17 5 2 (nil) [1 uses])
+(note 17 16 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 5 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 5 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 6 3 (nil) [1 uses])
+(note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 6 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 6 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
diff --git a/gcc/testsuite/rtl.dg/roundtrip/test-switch-after-expand.rtl b/gcc/testsuite/rtl.dg/roundtrip/test-switch-after-expand.rtl
new file mode 100644
index 0000000..497e671
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/test-switch-after-expand.rtl
@@ -0,0 +1,202 @@
+(note 1 0 7 (nil) NOTE_INSN_DELETED)
+(note 7 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 7 3 2 (set (reg/v:SI 88 [ i ])
+        (reg:SI 5 di [ i ])) ../../src/test-switch.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (reg/v:SI 89 [ j ])
+        (reg:SI 4 si [ j ])) ../../src/test-switch.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (reg/v:SI 90 [ k ])
+        (reg:SI 1 dx [ k ])) ../../src/test-switch.c:2 -1
+     (nil))
+(note 5 4 9 2 NOTE_INSN_FUNCTION_BEG)
+(insn 9 5 10 2 (parallel [
+            (set (reg:SI 91)
+                (plus:SI (reg/v:SI 88 [ i ])
+                    (const_int 1 [0x1])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/test-switch.c:3 -1
+     (nil))
+(insn 10 9 11 2 (set (reg:CC 17 flags)
+        (compare:CC (reg:SI 91)
+            (const_int 25 [0x19]))) ../../src/test-switch.c:3 -1
+     (nil))
+(jump_insn 11 10 67 2 (set (pc)
+        (if_then_else (gtu (reg:CC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 52)
+            (pc))) ../../src/test-switch.c:3 -1
+     (int_list:REG_BR_PROB 625 (nil))
+ -> 52)
+(note 67 11 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 67 13 4 (set (reg:DI 92)
+        (zero_extend:DI (reg:SI 91))) ../../src/test-switch.c:3 -1
+     (nil))
+(insn 13 12 14 4 (set (reg/f:DI 93)
+        (label_ref:DI 17)) ../../src/test-switch.c:3 -1
+     (insn_list:REG_LABEL_OPERAND 17 (nil)))
+(insn 14 13 15 4 (set (reg:DI 94)
+        (mem/u/c:DI (plus:DI (ashift:DI (reg:DI 92)
+                    (const_int 3 [0x3]))
+                (reg/f:DI 93)) [0  S8 A8])) ../../src/test-switch.c:3 -1
+     (nil))
+(jump_insn 15 14 16 4 (parallel [
+            (set (pc)
+                (reg:DI 94))
+            (use (label_ref 17))
+        ]) ../../src/test-switch.c:3 -1
+     (nil)
+ -> 17)
+(barrier 16 15 17)
+(code_label 17 16 18 (nil) 4 (nil) [2 uses])
+(jump_table_data 18 17 19 (nil) (addr_vec:DI [
+            (label_ref:DI 66)
+            (label_ref:DI 20)
+            (label_ref:DI 20)
+            (label_ref:DI 20)
+            (label_ref:DI 20)
+            (label_ref:DI 20)
+            (label_ref:DI 20)
+            (label_ref:DI 20)
+            (label_ref:DI 20)
+            (label_ref:DI 20)
+            (label_ref:DI 20)
+            (label_ref:DI 35)
+            (label_ref:DI 40)
+            (label_ref:DI 46)
+            (label_ref:DI 52)
+            (label_ref:DI 52)
+            (label_ref:DI 52)
+            (label_ref:DI 52)
+            (label_ref:DI 52)
+            (label_ref:DI 52)
+            (label_ref:DI 52)
+            (label_ref:DI 52)
+            (label_ref:DI 52)
+            (label_ref:DI 52)
+            (label_ref:DI 25)
+            (label_ref:DI 30)
+        ]))
+(barrier 19 18 20)
+(code_label 20 19 21 5 5 (nil) [10 uses])
+(note 21 20 22 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 23 5 (parallel [
+            (set (reg:SI 87 [ <retval> ])
+                (ashift:SI (reg/v:SI 88 [ i ])
+                    (const_int 1 [0x1])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/test-switch.c:8 -1
+     (nil))
+(jump_insn 23 22 24 5 (set (pc)
+        (label_ref:DI 59)) ../../src/test-switch.c:8 -1
+     (nil)
+ -> 59)
+(barrier 24 23 25)
+(code_label 25 24 26 6 9 (nil) [1 uses])
+(note 26 25 27 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 27 26 28 6 (parallel [
+            (set (reg:SI 87 [ <retval> ])
+                (plus:SI (reg/v:SI 89 [ j ])
+                    (reg/v:SI 90 [ k ])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/test-switch.c:10 -1
+     (nil))
+(jump_insn 28 27 29 6 (set (pc)
+        (label_ref:DI 59)) ../../src/test-switch.c:10 -1
+     (nil)
+ -> 59)
+(barrier 29 28 30)
+(code_label 30 29 31 7 10 (nil) [1 uses])
+(note 31 30 32 7 [bb 7] NOTE_INSN_BASIC_BLOCK)
+(insn 32 31 33 7 (parallel [
+            (set (reg:SI 87 [ <retval> ])
+                (minus:SI (reg/v:SI 89 [ j ])
+                    (reg/v:SI 90 [ k ])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/test-switch.c:12 -1
+     (nil))
+(jump_insn 33 32 34 7 (set (pc)
+        (label_ref:DI 59)) ../../src/test-switch.c:12 -1
+     (nil)
+ -> 59)
+(barrier 34 33 35)
+(code_label 35 34 36 8 6 (nil) [1 uses])
+(note 36 35 37 8 [bb 8] NOTE_INSN_BASIC_BLOCK)
+(insn 37 36 38 8 (parallel [
+            (set (reg:SI 87 [ <retval> ])
+                (mult:SI (reg/v:SI 89 [ j ])
+                    (reg/v:SI 90 [ k ])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/test-switch.c:14 -1
+     (nil))
+(jump_insn 38 37 39 8 (set (pc)
+        (label_ref:DI 59)) ../../src/test-switch.c:14 -1
+     (nil)
+ -> 59)
+(barrier 39 38 40)
+(code_label 40 39 41 9 7 (nil) [1 uses])
+(note 41 40 42 9 [bb 9] NOTE_INSN_BASIC_BLOCK)
+(insn 42 41 43 9 (parallel [
+            (set (reg:SI 95)
+                (div:SI (reg/v:SI 89 [ j ])
+                    (reg/v:SI 90 [ k ])))
+            (set (reg:SI 96)
+                (mod:SI (reg/v:SI 89 [ j ])
+                    (reg/v:SI 90 [ k ])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/test-switch.c:16 -1
+     (nil))
+(insn 43 42 44 9 (set (reg:SI 87 [ <retval> ])
+        (reg:SI 95)) ../../src/test-switch.c:16 -1
+     (nil))
+(jump_insn 44 43 45 9 (set (pc)
+        (label_ref:DI 59)) ../../src/test-switch.c:16 -1
+     (nil)
+ -> 59)
+(barrier 45 44 46)
+(code_label 46 45 47 10 8 (nil) [1 uses])
+(note 47 46 48 10 [bb 10] NOTE_INSN_BASIC_BLOCK)
+(insn 48 47 49 10 (parallel [
+            (set (reg:SI 98)
+                (div:SI (reg/v:SI 89 [ j ])
+                    (reg/v:SI 90 [ k ])))
+            (set (reg:SI 97)
+                (mod:SI (reg/v:SI 89 [ j ])
+                    (reg/v:SI 90 [ k ])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/test-switch.c:18 -1
+     (nil))
+(insn 49 48 50 10 (set (reg:SI 87 [ <retval> ])
+        (reg:SI 97)) ../../src/test-switch.c:18 -1
+     (nil))
+(jump_insn 50 49 51 10 (set (pc)
+        (label_ref:DI 59)) ../../src/test-switch.c:18 -1
+     (nil)
+ -> 59)
+(barrier 51 50 52)
+(code_label 52 51 53 11 2 (nil) [11 uses])
+(note 53 52 54 11 [bb 11] NOTE_INSN_BASIC_BLOCK)
+(insn 54 53 63 11 (parallel [
+            (set (reg:SI 87 [ <retval> ])
+                (plus:SI (reg/v:SI 89 [ j ])
+                    (reg/v:SI 90 [ k ])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/test-switch.c:20 -1
+     (nil))
+(jump_insn 63 54 64 11 (set (pc)
+        (label_ref:DI 59)) ../../src/test-switch.c:20 -1
+     (nil)
+ -> 59)
+(barrier 64 63 66)
+(code_label 66 64 65 12 11 (nil) [1 uses])
+(note 65 66 6 12 [bb 12] NOTE_INSN_BASIC_BLOCK)
+(insn 6 65 59 12 (set (reg:SI 87 [ <retval> ])
+        (const_int 34 [0x22])) ../../src/test-switch.c:6 -1
+     (nil))
+(code_label 59 6 62 14 1 (nil) [7 uses])
+(note 62 59 60 14 [bb 14] NOTE_INSN_BASIC_BLOCK)
+(insn 60 62 61 14 (set (reg/i:SI 0 ax)
+        (reg:SI 87 [ <retval> ])) ../../src/test-switch.c:22 -1
+     (nil))
+(insn 61 60 0 14 (use (reg/i:SI 0 ax)) ../../src/test-switch.c:22 -1
+     (nil))
diff --git a/gcc/testsuite/rtl.dg/rtl.exp b/gcc/testsuite/rtl.dg/rtl.exp
new file mode 100644
index 0000000..4225f78
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/rtl.exp
@@ -0,0 +1,43 @@
+#   Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib rtl-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_RTLFLAGS
+if ![info exists DEFAULT_RTLFLAGS] then {
+    set DEFAULT_RTLFLAGS ""
+    # -fdump-tree-rtl-raw
+}
+
+# Initialize `dg'.
+dg-init
+
+# Gather a list of all tests, with the exception of those in directories
+# that are handled specially.
+set tests [lsort [find $srcdir/$subdir *.rtl]]
+set tests [prune $tests $srcdir/$subdir/roundtrip/*]
+
+verbose "rtl.exp tests: $tests" 1
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_RTLFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/rtl.dg/test.c b/gcc/testsuite/rtl.dg/test.c
new file mode 100644
index 0000000..ebb8aef
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/test.c
@@ -0,0 +1,31 @@
+int test_1 (int i, int j, int k)
+{
+  if (i < j)
+    return k + 4;
+  else
+    return -k;
+}
+
+/* Example showing:
+   - data structure
+   - loop
+   - call to "abort".  */
+
+struct foo
+{
+  int count;
+  float *data;
+};
+
+float test_2 (struct foo *lhs, struct foo *rhs)
+{
+  float result = 0.0f;
+
+  if (lhs->count != rhs->count)
+    __builtin_abort ();
+
+  for (int i = 0; i < lhs->count; i++)
+    result += lhs->data[i] * rhs->data[i];
+
+  return result;
+}
diff --git a/gcc/testsuite/rtl.dg/unknown-insn-uid.rtl b/gcc/testsuite/rtl.dg/unknown-insn-uid.rtl
new file mode 100644
index 0000000..c91bf4a
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/unknown-insn-uid.rtl
@@ -0,0 +1,3 @@
+(note 6 1 0 2 [bb 2] NOTE_INSN_BASIC_BLOCK) ;; { dg-error "insn with UID 1 not found for operand 0 ..PREV_INSN.. of insn 6" }
+
+(note 7 0 3 2 [bb 2] NOTE_INSN_BASIC_BLOCK) ;; { dg-error "insn with UID 3 not found for operand 1 ..NEXT_INSN.. of insn 7" }
diff --git a/gcc/testsuite/rtl.dg/unknown-rtx-code.rtl b/gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
new file mode 100644
index 0000000..7a66767
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
@@ -0,0 +1 @@
+(not-a-valid-kind-of-insn 1 0 0) ;; { dg-error "unknown rtx code" }
diff --git a/gcc/testsuite/rtl.dg/vregs.rtl b/gcc/testsuite/rtl.dg/vregs.rtl
new file mode 100644
index 0000000..23e4cc0
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/vregs.rtl
@@ -0,0 +1,80 @@
+/* { dg-options "-fsingle-pass=rtl-vregs -fdump-rtl-vregs" } */
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 4 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 14 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 14 13 15 4 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 15 14 16)
+(code_label 16 15 17 5 2 (nil) [1 uses])
+(note 17 16 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 5 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 5 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 6 3 (nil) [1 uses])
+(note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 6 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 6 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+
+/* The 9 instances of "virtual-stack-vars" should now all be "frame".  */
+/* { dg-final { scan-rtl-dump-times "frame" 9 "vregs" } }  */
+/* { dg-final { scan-rtl-dump-not "virtual-stack-vars" "vregs" } }  */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 580c03a..d308404 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -473,6 +473,13 @@ compile_file (void)
 
   if (flag_syntax_only || flag_wpa)
     return;
+
+  /* The RTL frontend is currently only capable of running one pass; this
+     is done from within the parse_file langhook.
+     Hence we must return early here.  Fixing this would require
+     being able to run passes from a certain point onwards.  */
+  if (in_rtl_frontend_p)
+    return;
  
   /* Reset maximum_field_alignment, it can be adjusted by #pragma pack
      and this shouldn't influence any types built by the middle-end
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index f6986c1..149db53 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 rtl1.  */
+  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



More information about the Gcc-patches mailing list