From 7dce9474af1b9d3d0e22cb90f2a35f924c8861a7 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 18 Mar 2016 17:56:28 -0400
Subject: [PATCH 09/15] FIXME: RTL frontend

Individual commit messages were:
FIXME: enough to build an rtl1

FIXME: add TODO.rst

FIXME: call read_md_files from rtl-frontend.c

FIXME: driver support

FIXME: a test file, cleaned to just one function, and without log spew

FIXME: enough hacks to allow running read-rtl.c inside RTL frontend (which then fails)

FIXME: enough hacks to read the first note insn in the test

FIXME: handle INSN_UID, flags, and extra text for 'r'

FIXME: handle 'w'

FIXME: enough to parse first insn

FIXME: handle EXPR_LIST etc; handle CODE_LABEL

FIXME: insn ref fixup

FIXME: disable the insns we can't handle, for now

FIXME: the test-loop.c source

FIXME: start introducing rtx_reader class

FIXME: move more rtx parsing into rtx_reader

FIXME: use libcpp for location-handling

FIXME: use 'inform' within fatal_with_file_and_line

FIXME: handle insns with NULL basic block

FIXME: error_at rather than error when insn UID not found

FIXME: don't fixup UID 0

FIXME: add operand names to errors

FIXME: initial version of column-handling

FIXME: make read_name return start location

FIXME: make read_name return a range

FIXME: attempt to print source insns

FIXME: include the closing parenthesis

FIXME: more read_char/unread_char into rtx_reader

FIXME: move lineno/colno into rtx_reader

FIXME: move read_md_file into rtx_reader

FIXME: improve location for fatal_with_file_and_line

FIXME: handle note-specific data for NOTE_INSN_BASIC_BLOCK

FIXME: handle insns that don't have a source location

FIXME: consolidate fixup handling

FIXME: create function and cfg; reconstruct XBBDEF within each insn

FIXME: set up BB_HEAD and BB_END

FIXME: attempt to roundtrip the RTL

FIXME: fix the NOTE_BASIC_BLOCK of NOTE_INSN_BASIC_BLOCK

FIXME: minor tweak to add_fixup_bb

FIXME: reduce debug spew

FIXME: use deferred locations to implement fixup of INSN_LOCATION

FIXME: reduce more debug spew

FIXME: handle numeric JUMP_LABEL values

FIXME: parse LABEL_NUSES

FIXME: introduce require_char etc

FIXME: simplify reg parsing

FIXME: set default value for ORIGINAL_REGNO

FIXME: handle <retval> for REG_EXPR

FIXME: populate x_crtl; more typesafety

FIXME: for now, don't require fndecl to have a DECL_INITIAL within instantiate_decls

FIXME: hack to run one pass

FIXME: start consolidating singletons

FIXME: get pass by name within rtl-frontend.c

FIXME: handle MEM_SIZE, MEM_ALIGN, MEM_ADDR_SPACE

FIXME: consolidate singletons; enables pass 'vregs' to work

FIXME: call initialize_rtl (needed to set flags on singletons)

FIXME: set MEM_OFFSET_KNOWN_P and MEM_OFFSET

FIXME: handle MEM_EXPR, in theory, at least

FIXME: automatically fake locals etc

FIXME: dump NULL strings as (nil)

FIXME: WIP on DejaGnu support

FIXME: reduce debug spew

FIXME: tweak code-labels.rtl

FIMXE: add test of switch (with jump_table_data)

FIXME: add notes.rst

FIXME: start adding tests of error-handling

FIXME: handle return/simple_return values for JUMP_LABEL

FIXME: tests of 'include'

FIXME: roundtrip.exp: delete output file

FIXME: move read_md_filename into rtx_reader

FIXME: make rtx_reader instance survive init_rtx_reader_args[_cb]

FIXME: move in_fname into rtx_reader and rename to m_toplevel_fname

FIXME: missing part of FIXME: make rtx_reader instance survive init_rtx_reader_args[_cb]

FIXME: move first_dir_md_include and last_dir_md_include_ptr into rtx_reader; eliminate max_include_len

FIXME: move base_dir into rtx_reader

FIXME: update linemaps in include handling

FIXME: fixes to include tests

FIXME: fix output from fatal_with_file_and_line

FIXME: add -fsingle-pass= option

FIXME: rename test case

FIXME: move flag parsing into its own function

FIXME: fix creation of basic blocks

FIXME: introduce function_reader::create_cfg

FIXME: break out function_reader ctor

FIXME: more singleton consolidation

FIXME: create edges in CFG

FIXME: more notes.rst

FIXME: add into-cfglayout.rtl

FIXME: add notes about cfgrtl vs cfglayout mode

FIXME: fix typo in vregs.rtl

FIXME: more on into-cfglayout.rtl

FIXME: set last_basic_block_for_fn

FIXME: ensure regno_reg_rtx is populated

FIXME: set up x_cur_insn_uid

FIXME: another blob of merged commits

FIXME: get dfinit.rtl working

FIXME: properly initialize entry and exit blocks

FIXME: move code from pass_expand::execute to rtl_data::init_stack_alignment

FIXME: run df if necessary; ensure reg_obstack is initialized

FIXME: get ira working (requires adding cgraph node)

FIXME: work towards getting reload to work

FIXME: fix parsing of regs with ORIGINAL_REGNO set

FIXME: get pro_and_epilogue working

FIXME: parse INSN_UID *after* mode

FIXME: handle RETURN/SIMPLE_RETURN in for_each_label_ref

FIXME: Get 'final' working
---
 gcc/Makefile.in                                    |   27 +-
 gcc/cfgexpand.c                                    |    7 +-
 gcc/emit-rtl.c                                     |   15 +-
 gcc/emit-rtl.h                                     |    2 +
 gcc/function.c                                     |   41 +-
 gcc/function.h                                     |    2 +-
 gcc/gcc.c                                          |    1 +
 gcc/genattrtab.c                                   |   13 +-
 gcc/genconstants.c                                 |    5 +-
 gcc/genemit.c                                      |   28 +-
 gcc/genenums.c                                     |    5 +-
 gcc/genmddeps.c                                    |    5 +-
 gcc/genoutput.c                                    |    6 +-
 gcc/genpreds.c                                     |    9 +-
 gcc/gensupport.c                                   |   32 +-
 gcc/gensupport.h                                   |    6 +-
 gcc/pass_manager.h                                 |    1 +
 gcc/print-rtl.c                                    |    4 +-
 gcc/read-md.c                                      |  481 ++++++--
 gcc/read-md.h                                      |  155 ++-
 gcc/read-rtl.c                                     |  685 ++++++++++-
 gcc/rtl.c                                          |    2 +
 gcc/rtl.h                                          |    5 +
 gcc/rtl/Make-lang.in                               |  148 +++
 gcc/rtl/TODO.rst                                   |   16 +
 gcc/rtl/config-lang.in                             |   36 +
 gcc/rtl/lang-specs.h                               |   25 +
 gcc/rtl/lang.opt                                   |   36 +
 gcc/rtl/notes.rst                                  |  131 ++
 gcc/rtl/rtl-errors.c                               |   32 +
 gcc/rtl/rtl-frontend.c                             | 1257 ++++++++++++++++++++
 gcc/testsuite/lib/rtl-dg.exp                       |   59 +
 gcc/testsuite/rtl.dg/bad-include.rtl               |    5 +
 gcc/testsuite/rtl.dg/bad-includee.md               |    5 +
 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           |    5 +
 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       |   82 ++
 .../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/unknown-insn-uid.rtl          |   11 +
 gcc/testsuite/rtl.dg/unknown-rtx-code.rtl          |    5 +
 gcc/testsuite/rtl.dg/vregs.rtl                     |   80 ++
 gcc/toplev.c                                       |    7 +
 gcc/tree-dfa.c                                     |    5 +
 test-loop.c                                        |   31 +
 61 files changed, 3966 insertions(+), 256 deletions(-)
 create mode 100644 gcc/rtl/Make-lang.in
 create mode 100644 gcc/rtl/TODO.rst
 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/bad-include.rtl
 create mode 100644 gcc/testsuite/rtl.dg/bad-includee.md
 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/unknown-insn-uid.rtl
 create mode 100644 gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
 create mode 100644 gcc/testsuite/rtl.dg/vregs.rtl
 create mode 100644 test-loop.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c61f303..72d3cf8 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1047,7 +1047,7 @@ LDEXP_LIB = @LDEXP_LIB@
 
 # Likewise, for use in the tools that must run on this machine
 # even if we are cross-building GCC.
-BUILD_LIBS = $(BUILD_LIBIBERTY)
+BUILD_LIBS = $(BUILD_CPPLIB) $(BUILD_LIBIBERTY)
 
 BUILD_RTL = build/rtl.o build/read-rtl.o build/ggc-none.o \
 	    build/vec.o build/min-insn-modes.o build/gensupport.o \
@@ -2591,29 +2591,32 @@ build/gengtype.o: $(BCONFIG_H)
 CFLAGS-errors.o += -DHOST_GENERATOR_FILE
 
 build/genmddeps.o: genmddeps.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h	\
-  errors.h $(READ_MD_H)
+  errors.h $(READ_MD_H) $(BUILD_CPPLIB)
 build/genmodes.o : genmodes.c $(BCONFIG_H) $(SYSTEM_H) errors.h		\
-  $(HASHTAB_H) machmode.def $(extra_modes_file)
+  $(HASHTAB_H) machmode.def $(extra_modes_file) $(BUILD_CPPLIB)
 build/genopinit.o : genopinit.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H)	\
-  coretypes.h $(GTM_H) errors.h $(GENSUPPORT_H) optabs.def
+  coretypes.h $(GTM_H) errors.h $(GENSUPPORT_H) optabs.def $(BUILD_CPPLIB)
 build/genoutput.o : genoutput.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H)	\
-  coretypes.h $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H)
+  coretypes.h $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H) $(BUILD_CPPLIB)
 build/genpeep.o : genpeep.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H)	\
-  coretypes.h $(GTM_H) errors.h $(GENSUPPORT_H) toplev.h $(DIAGNOSTIC_CORE_H)
+  coretypes.h $(GTM_H) errors.h $(GENSUPPORT_H) toplev.h $(DIAGNOSTIC_CORE_H) \
+  $(BUILD_CPPLIB)
 build/genpreds.o : genpreds.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H)	\
-  coretypes.h $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H) $(OBSTACK_H)
+  coretypes.h $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H) $(OBSTACK_H) \
+  $(BUILD_CPPLIB)
 build/genrecog.o : genrecog.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H)	\
   coretypes.h $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H)		\
-  $(HASH_TABLE_H) inchash.h
+  $(HASH_TABLE_H) inchash.h $(BUILD_CPPLIB)
 build/genhooks.o : genhooks.c $(TARGET_DEF) $(C_TARGET_DEF)		\
-  $(COMMON_TARGET_DEF) $(BCONFIG_H) $(SYSTEM_H) errors.h
+  $(COMMON_TARGET_DEF) $(BCONFIG_H) $(SYSTEM_H) errors.h $(BUILD_CPPLIB)
 build/genmddump.o : genmddump.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H)	\
-  coretypes.h $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H)
+  coretypes.h $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H) $(BUILD_CPPLIB)
 build/genmatch.o : genmatch.c $(BCONFIG_H) $(SYSTEM_H) \
   coretypes.h errors.h $(HASH_TABLE_H) hash-map.h $(GGC_H) is-a.h \
-  tree.def builtins.def internal-fn.def
+  tree.def builtins.def internal-fn.def $(BUILD_CPPLIB)
 build/gencfn-macros.o : gencfn-macros.c $(BCONFIG_H) $(SYSTEM_H)	\
-  coretypes.h errors.h $(HASH_TABLE_H) hash-set.h builtins.def internal-fn.def
+  coretypes.h errors.h $(HASH_TABLE_H) hash-set.h builtins.def internal-fn.def \
+  $(BUILD_CPPLIB)
 
 # Compile the programs that generate insn-* from the machine description.
 # They are compiled with $(COMPILER_FOR_BUILD), and associated libraries,
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..6a45376 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 ();
     }
 }
+
+/* FIXME.  */
+
+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/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/genattrtab.c b/gcc/genattrtab.c
index 91d04d4..7bed462 100644
--- a/gcc/genattrtab.c
+++ b/gcc/genattrtab.c
@@ -4235,9 +4235,12 @@ write_insn_cases (FILE *outf, struct insn_ent *ie, int indent)
       {
 	write_indent (outf, indent);
 	if (GET_CODE (ie->def->def) == DEFINE_PEEPHOLE)
-	  fprintf (outf, "case %d:  /* define_peephole, %s:%d */\n",
-		   ie->def->insn_code, ie->def->loc.filename,
-		   ie->def->loc.lineno);
+	  {
+	    expanded_location xloc
+	      = linemap_client_expand_location_to_spelling_point (ie->def->loc);
+	    fprintf (outf, "case %d:  /* define_peephole, %s:%d */\n",
+		     ie->def->insn_code, xloc.file, xloc.line);
+	  }
 	else
 	  fprintf (outf, "case %d:  /* %s */\n",
 		   ie->def->insn_code, XSTR (ie->def->def, 0));
@@ -4638,7 +4641,7 @@ make_internal_attr (const char *name, rtx value, int special)
   attr->is_numeric = 1;
   attr->is_const = 0;
   attr->is_special = (special & ATTR_SPECIAL) != 0;
-  attr->default_val = get_attr_value (file_location ("<internal>", 0),
+  attr->default_val = get_attr_value (GENERATOR_BUILTINS_LOCATION,
 				      value, attr, -2);
 }
 
@@ -5260,7 +5263,7 @@ main (int argc, const char **argv)
       md_rtx_info info;
       info.def = rtx_alloc (DEFINE_ASM_ATTRIBUTES);
       XVEC (info.def, 0) = rtvec_alloc (0);
-      info.loc = file_location ("<internal>", 0);
+      info.loc = GENERATOR_BUILTINS_LOCATION;
       info.index = -1;
       gen_insn (&info);
     }
diff --git a/gcc/genconstants.c b/gcc/genconstants.c
index c10e3e3..c785d31 100644
--- a/gcc/genconstants.c
+++ b/gcc/genconstants.c
@@ -79,7 +79,10 @@ main (int argc, const char **argv)
 {
   progname = "genconstants";
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  line_maps line_table;
+  generator_linemap_init (&line_table);
+  noop_reader reader (&line_table);
+  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/genemit.c b/gcc/genemit.c
index 33040aa..d28e2e2 100644
--- a/gcc/genemit.c
+++ b/gcc/genemit.c
@@ -397,7 +397,9 @@ gen_insn (md_rtx_info *info)
   if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*')
     return;
 
-  printf ("/* %s:%d */\n", info->loc.filename, info->loc.lineno);
+  expanded_location xloc
+    = linemap_client_expand_location_to_spelling_point (info->loc);
+  printf ("/* %s:%d */\n", xloc.file, xloc.line);
 
   /* Find out how many operands this function has.  */
   get_pattern_stats (&stats, XVEC (insn, 1));
@@ -808,18 +810,30 @@ from the machine description file `md'.  */\n\n");
 	break;
 
       case DEFINE_EXPAND:
-	printf ("/* %s:%d */\n", info.loc.filename, info.loc.lineno);
-	gen_expand (&info);
+	{
+	  expanded_location xloc
+	    = linemap_client_expand_location_to_spelling_point (info.loc);
+	  printf ("/* %s:%d */\n", xloc.file, xloc.line);
+	  gen_expand (&info);
+	}
 	break;
 
       case DEFINE_SPLIT:
-	printf ("/* %s:%d */\n", info.loc.filename, info.loc.lineno);
-	gen_split (&info);
+	{
+	  expanded_location xloc
+	    = linemap_client_expand_location_to_spelling_point (info.loc);
+	  printf ("/* %s:%d */\n", xloc.file, xloc.line);
+	  gen_split (&info);
+	}
 	break;
 
       case DEFINE_PEEPHOLE2:
-	printf ("/* %s:%d */\n", info.loc.filename, info.loc.lineno);
-	gen_split (&info);
+	{
+	  expanded_location xloc
+	    = linemap_client_expand_location_to_spelling_point (info.loc);
+	  printf ("/* %s:%d */\n", xloc.file, xloc.line);
+	  gen_split (&info);
+	}
 	break;
 
       default:
diff --git a/gcc/genenums.c b/gcc/genenums.c
index db46a67..22f8110 100644
--- a/gcc/genenums.c
+++ b/gcc/genenums.c
@@ -49,7 +49,10 @@ main (int argc, const char **argv)
 {
   progname = "genenums";
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  line_maps line_table;
+  generator_linemap_init (&line_table);
+  noop_reader reader (&line_table);
+  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..9b5eafc 100644
--- a/gcc/genmddeps.c
+++ b/gcc/genmddeps.c
@@ -47,7 +47,10 @@ main (int argc, const char **argv)
   progname = "genmddeps";
   include_callback = add_filedep;
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  line_maps line_table;
+  generator_linemap_init (&line_table);
+  noop_reader reader (&line_table);
+  if (!reader.read_md_files (argc, argv, NULL))
     return FATAL_EXIT_CODE;
 
   *last = NULL;
diff --git a/gcc/genoutput.c b/gcc/genoutput.c
index f8c25ac..3241115 100644
--- a/gcc/genoutput.c
+++ b/gcc/genoutput.c
@@ -292,7 +292,9 @@ output_insn_data (void)
 
   for (d = idata; d; d = d->next)
     {
-      printf ("  /* %s:%d */\n", d->loc.filename, d->loc.lineno);
+      expanded_location xloc
+	= linemap_client_expand_location_to_spelling_point (d->loc);
+      printf ("  /* %s:%d */\n", xloc.file, xloc.line);
       printf ("  {\n");
 
       if (d->name)
@@ -979,7 +981,7 @@ init_insn_for_nothing (void)
   idata = XCNEW (struct data);
   new (idata) data ();
   idata->name = "*placeholder_for_nothing";
-  idata->loc = file_location ("<internal>", 0);
+  idata->loc = GENERATOR_BUILTINS_LOCATION;
   idata_end = &idata->next;
 }
 
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..c60364b 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -446,7 +446,7 @@ add_define_attr (const char *name)
   XEXP (t1, 2) = rtx_alloc (CONST_STRING);
   XSTR (XEXP (t1, 2), 0) = "yes";
   e->data = t1;
-  e->loc = file_location ("built-in", -1);
+  e->loc = GENERATOR_BUILTINS_LOCATION;
   e->next = define_attr_queue;
   define_attr_queue = e;
 
@@ -2226,10 +2226,17 @@ process_define_subst (void)
     }
 }
 
-/* A read_md_files callback for reading an rtx.  */
+/* FIXME.  */
 
-static void
-rtx_handle_directive (file_location loc, const char *rtx_name)
+class gen_reader : public rtx_reader
+{
+ public:
+  gen_reader (line_maps *line_table) : rtx_reader (line_table) {}
+  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 +2507,7 @@ check_define_attr_duplicates ()
 
 /* The entry point for initializing the reader.  */
 
-bool
+rtx_reader *
 init_rtx_reader_args_cb (int argc, const char **argv,
 			 bool (*parse_opt) (const char *))
 {
@@ -2516,7 +2523,10 @@ 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);
+  line_maps *line_table = XCNEW (struct line_maps);
+  generator_linemap_init (line_table);
+  gen_reader *reader = new gen_reader (line_table);
+  reader->read_md_files (argc, argv, parse_opt);
 
   if (define_attr_queue != NULL)
     check_define_attr_duplicates ();
@@ -2532,12 +2542,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/pass_manager.h b/gcc/pass_manager.h
index 464e25f..89b307a 100644
--- a/gcc/pass_manager.h
+++ b/gcc/pass_manager.h
@@ -105,6 +105,7 @@ private:
   context *m_ctxt;
   hash_map<nofree_string_hash, opt_pass *> *m_name_to_pass_map;
 
+ public:
   /* References to all of the individual passes.
      These fields are generated via macro expansion.
 
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..56d1a62 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -22,6 +22,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "errors.h"
 #include "read-md.h"
+#ifndef GENERATOR_FILE
+#include "diagnostic.h"
+#endif
 
 /* Associates PTR (which can be a string, etc.) with the file location
    specified by FILENAME and LINENO.  */
@@ -31,12 +34,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 +53,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;
+/* FIXME.  */
+
+rtx_reader *rtx_reader_ptr;
 
 /* A table of md_constant structures, hashed by name.  Null if no
    constant expansion should occur.  */
@@ -92,7 +68,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.  */
@@ -241,13 +217,17 @@ print_c_condition (const char *cond)
   fprint_c_condition (stdout, cond);
 }
 
+#ifdef GENERATOR_FILE
+
 /* A vfprintf-like function for reporting an error against line LINENO
    of the current MD file.  */
 
 static void ATTRIBUTE_PRINTF(2,0)
 message_at_1 (file_location loc, const char *msg, va_list ap)
 {
-  fprintf (stderr, "%s:%d: ", loc.filename, loc.lineno);
+  expanded_location xloc
+    = linemap_client_expand_location_to_spelling_point (loc);
+  fprintf (stderr, "%s:%d: ", xloc.file, xloc.line);
   vfprintf (stderr, msg, ap);
   fputc ('\n', stderr);
 }
@@ -289,6 +269,7 @@ fatal_at (file_location loc, const char *msg, ...)
   va_end (ap);
   exit (1);
 }
+#endif /* #ifdef GENERATOR_FILE */
 
 /* A printf-like function for reporting an error against the current
    position in the MD file.  */
@@ -296,6 +277,7 @@ fatal_at (file_location loc, const char *msg, ...)
 void
 fatal_with_file_and_line (const char *msg, ...)
 {
+#ifdef GENERATOR_FILE
   char context[64];
   size_t i;
   int c;
@@ -303,7 +285,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: ", rtx_reader_ptr->get_filename (),
+	   rtx_reader_ptr->get_lineno ());
   vfprintf (stderr, msg, ap);
   putc ('\n', stderr);
 
@@ -323,9 +306,21 @@ 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);
+	   rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+	   context);
 
   va_end (ap);
+#else /* #ifdef GENERATOR_FILE */
+  diagnostic_info diagnostic;
+  va_list ap;
+  file_location loc = rtx_reader_ptr->get_current_location ();
+  rich_location richloc (line_table, loc);
+  va_start (ap, msg);
+  diagnostic_set_info (&diagnostic, msg, &ap, &richloc, DK_ERROR);
+  report_diagnostic (&diagnostic);
+  va_end (ap);
+#endif  /* #else of #ifdef GENERATOR_FILE */
+
   exit (1);
 }
 
@@ -372,7 +367,7 @@ read_skip_spaces (void)
 	    if (c != '*')
 	      {
 		unread_char (c);
-		fatal_with_file_and_line ("stray '/' in file");
+		return '/';
 	      }
 
 	    prevc = 0;
@@ -391,11 +386,123 @@ 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);
+}
+
+/* FIXME.  */
+
+file_location
+rtx_reader::make_location (file_location caret, file_location start,
+			   file_location finish) const
+{
+  source_range src_range;
+  src_range.m_start = start;
+  src_range.m_finish = finish;
+  file_location combined_loc = COMBINE_LOCATION_DATA (m_line_table,
+						      caret,
+						      src_range,
+						      NULL);
+  return combined_loc;
+}
+
+/* FIXME.  */
+
+int
+rtx_reader::read_char (void)
+{
+  int ch;
+
+  ch = getc (m_read_md_file);
+  if (ch == '\n')
+    {
+      m_read_md_lineno++;
+      m_read_md_colno = 0;
+    }
+  else
+    m_read_md_colno++;
+
+  update_location (true);
+
+  return ch;
+}
+
+/* FIXME.  */
+
+void
+rtx_reader::unread_char (int ch)
+{
+  /* FIXME: what about colno when unreading a '\n'? */
+  if (ch == '\n')
+    m_read_md_lineno--;
+  else
+    m_read_md_colno--;
+  update_location (false);
+  ungetc (ch, m_read_md_file);
+}
+
+/* FIXME.  */
+int peek_char (void)
+{
+  int ch = read_char ();
+  unread_char (ch);
+  return ch;
+}
+
+/* FIXME.  */
+int peek_char_2 (void)
+{
+  int ch_1 = read_char ();
+  int ch_2 = read_char ();
+  unread_char (ch_2);
+  unread_char (ch_1);
+  return ch_2;
+}
+
+/* FIXME.  */
+int peek_char_3 (void)
+{
+  int ch_1 = read_char ();
+  int ch_2 = read_char ();
+  int ch_3 = read_char ();
+  unread_char (ch_3);
+  unread_char (ch_2);
+  unread_char (ch_1);
+  return ch_3;
+}
+
 /* 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;
@@ -403,6 +510,8 @@ read_name (struct md_name *name)
 
   c = read_skip_spaces ();
 
+  file_location start = rtx_reader_ptr->get_current_location ();
+
   i = 0;
   angle_bracket_depth = 0;
   while (1)
@@ -433,8 +542,13 @@ read_name (struct md_name *name)
       c = read_char ();
     }
 
+  unread_char (c);
+  file_location end = rtx_reader_ptr->get_current_location ();
+  read_char ();
+  *out_loc = rtx_reader_ptr->make_location (start, start, end);
+
   if (i == 0)
-    fatal_with_file_and_line ("missing name or number");
+    return false;
 
   name->buffer[i] = 0;
   name->string = name->buffer;
@@ -455,6 +569,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 +645,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 +689,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 +735,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 +744,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 +913,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 +929,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 +991,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,17 +1043,49 @@ traverse_enum_types (htab_trav callback, void *info)
   htab_traverse (enum_types, callback, info);
 }
 
+
+/* FIXME.  */
+
+static line_maps *rtx_reader_line_table;
+
+/* FIXME.  */
+
+rtx_reader::rtx_reader (line_maps *line_table)
+: m_line_table (line_table),
+  m_current_linemap (NULL),
+  m_toplevel_fname (NULL),
+  m_read_md_filename (NULL),
+  m_read_md_lineno (0),
+  m_read_md_colno (0),
+  m_first_dir_md_include (NULL),
+  m_last_dir_md_include_ptr (&m_first_dir_md_include)
+{
+  rtx_reader_line_table = m_line_table;
+  rtx_reader_ptr = this;
+}
+
+/* FIXME.  */
+
+rtx_reader::~rtx_reader ()
+{
+#if 0
+  rtx_reader_line_table = NULL;
+#endif
+  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;
   int old_lineno;
+  int old_colno;
   char *pathname;
   FILE *input_file, *old_file;
 
@@ -923,7 +1098,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 +1114,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 +1131,31 @@ 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;
+  old_colno = m_read_md_colno;
 
   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;
+  m_current_linemap =
+    linemap_check_ordinary (linemap_add (m_line_table, LC_ENTER, 0,
+					 pathname, 1));
+
+  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;
+  m_read_md_colno = old_colno;
+
+  m_current_linemap =
+    linemap_check_ordinary (linemap_add (m_line_table, LC_LEAVE, 0,
+					 NULL, 0));
 
   /* Do not free the pathname.  It is attached to the various rtx
      queue elements.  */
@@ -980,16 +1165,17 @@ 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;
+  m_read_md_colno = 0;
   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 +1187,72 @@ 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);
+
+  m_current_linemap
+    = linemap_check_ordinary (linemap_add (m_line_table, LC_ENTER, 0,
+					   m_toplevel_fname, 1));
 
-  handle_file (handle_directive);
+  handle_file ();
+}
+
+file_location
+rtx_reader::get_current_location () const
+{
+  return linemap_position_for_line_and_column (m_line_table,
+					       m_current_linemap,
+					       m_read_md_lineno,
+					       m_read_md_colno);
+}
+
+/* FIXME.  */
+
+void
+rtx_reader::update_location (bool advancing)
+{
+  if (advancing)
+    {
+      if (m_read_md_lineno == 0)
+	linemap_line_start (m_line_table, m_read_md_lineno,
+			    1024 /* max_column_hint */);
+      linemap_position_for_column (m_line_table, m_read_md_colno);
+    }
 }
 
 /* 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 +1262,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 +1304,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 +1334,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 +1352,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 +1367,51 @@ 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);
+}
+
+#ifdef GENERATOR_FILE
+
+expanded_location
+linemap_client_expand_location_to_spelling_point (source_location loc)
+{
+  const struct line_map_ordinary *map;
+  loc = linemap_resolve_location (rtx_reader_line_table, loc,
+				  LRK_SPELLING_LOCATION, &map);
+  return linemap_expand_location (rtx_reader_line_table, map, loc);
+}
+
+#endif
+
+/* Helper for the linemap code.  */
+
+static size_t
+round_alloc_size (size_t s)
+{
+  return s;
+}
+
+/* FIXME.  */
+
+void
+generator_linemap_init (line_maps *line_table)
+{
+  linemap_init (line_table, 1);
+  line_table->reallocator = xrealloc;
+  line_table->round_alloc_size = round_alloc_size;
+  line_table->default_range_bits = 0;
+}
diff --git a/gcc/read-md.h b/gcc/read-md.h
index fc3b077..7968c7d 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -21,18 +21,9 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_READ_MD_H
 
 #include "obstack.h"
+#include "line-map.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) {}
+typedef source_location file_location;
 
 /* Holds one symbol or number in the .md file.  */
 struct md_name {
@@ -90,16 +81,114 @@ 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 (line_maps *line_table);
+  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;
+
+  /* FIXME.  */
+  virtual void add_fixup_insn_uid (file_location /*loc*/, rtx /*insn*/,
+				   int /*operand_idx*/, int /*insn_uid*/)
+  {}
+
+  virtual void add_fixup_bb (file_location /*loc*/, rtx /*insn*/,
+			     int /*operand_idx*/, int /*bb_idx*/)
+  {}
+
+  virtual void add_fixup_note_insn_basic_block (file_location /*loc*/,
+						rtx /*insn*/,
+						int /*operand_idx*/,
+						int /*bb_idx*/)
+  {}
+
+  virtual void add_fixup_source_location (file_location /*loc*/, rtx /*insn*/,
+					  int /*operand_idx*/,
+					  const char */*filename*/,
+					  int /*lineno*/)
+  {}
+
+  virtual void add_fixup_jump_label (file_location /*loc*/, rtx /*insn*/,
+				     int /*operand_idx*/,
+				     const char */*label*/)
+  {}
+
+  virtual void add_fixup_expr (file_location /*loc*/, rtx /*x*/,
+			       const char */*desc*/)
+  {}
+
+  file_location get_current_location () const;
+
+  void update_location (bool advancing);
+
+  file_location
+  make_location (file_location caret, file_location start,
+		 file_location finish) 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:
+  line_maps *m_line_table;
+  const line_map_ordinary *m_current_linemap;
+
+  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;
+
+  const char *m_read_md_filename;
+  int m_read_md_lineno;
+  int m_read_md_colno;
+
+  /* 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;
+
+class noop_reader : public rtx_reader
+{
+ public:
+  noop_reader (line_maps *line_table) : rtx_reader (line_table) {}
+
+  /* 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 +197,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 +205,13 @@ 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 int peek_char_2 (void);
+extern int peek_char_3 (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 +227,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 +240,8 @@ 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);
+
+#define GENERATOR_BUILTINS_LOCATION ((file_location) 1)
+extern void generator_linemap_init (line_maps *line_table);
 
 #endif /* GCC_READ_MD_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 79f42bf..75e9e80 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,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "read-md.h"
 #include "gensupport.h"
 
+#ifndef GENERATOR_FILE
+#include "diagnostic.h"
+#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 +118,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 +193,8 @@ apply_int_iterator (void *loc, int value)
   *(int *)loc = value;
 }
 
+#ifdef GENERATOR_FILE
+
 /* This routine adds attribute or does nothing depending on VALUE.  When
    VALUE is 1, it does nothing - the first duplicate of original
    template is kept untouched when it's subjected to a define_subst.
@@ -234,6 +248,7 @@ apply_subst_iterator (void *loc, int value)
     }
   XVEC (rt, 4) = new_attrs_vec;
 }
+#endif /* #ifdef GENERATOR_FILE */
 
 /* Map subst-attribute ATTR to subst iterator ITER.  */
 
@@ -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)
@@ -890,9 +907,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 +927,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);
@@ -929,6 +942,7 @@ read_mapping (struct iterator_group *group, htab_t table)
    'yes' and 'no'.  This attribute is used to mark templates to which
    define_subst ATTR_NAME should be applied.  This attribute is set and
    defined implicitly and automatically.  */
+#ifdef GENERATOR_FILE
 static void
 add_define_attr_for_define_subst (const char *attr_name, vec<rtx> *queue)
 {
@@ -1030,14 +1044,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 +1099,194 @@ 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);
+}
+#endif /* #ifndef GENERATOR_FILE */
+
+/* FIXME.  */
+
+#ifndef GENERATOR_FILE
+
+/* 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 ();
+  //inform (loc, "got filename: %qs", filename);
+  struct md_name name;
+  read_name (&name);
+  //inform (loc, "got line: %qs", name.string);
+
+  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 +1303,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 +1326,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 +1359,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 +1373,71 @@ 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
+	    if (0)
+	      inform (rtx_reader_ptr->get_current_location (),
+		      "note-specific data here");
+	    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 %qs", "bb");
+		file_location bb_idx_loc = 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
+	    if (0)
+	      inform (rtx_reader_ptr->get_current_location (),
+		      "jump_insn-specific data here");
+	    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 +1459,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 +1510,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 +1524,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 +1532,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 +1592,60 @@ read_rtx_code (const char *code_name)
 #endif
 #endif
 	XWINT (return_rtx, i) = tmp_wide;
+#ifndef GENERATOR_FILE
+	/* Strip away the hex.  */
+	{
+	  require_char_ws ('[');
+	  read_name (&name);
+	  //fprintf (stderr, "FIXME: ignoring `%s'\n", name.string);
+	  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
+
+	{
+	  // FIXME: print_rtx only writes out operand 5 for notes if:
+	  /* if (NOTE_KIND (in_rtx) == NOTE_INSN_DELETED_LABEL
+		|| NOTE_KIND (in_rtx) == 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);
+	    // generated by:
+	    // fprintf (outfile, " %s", GET_NOTE_INSN_NAME (XINT (in_rtx, i)));
+	  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 +1653,165 @@ 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;
+	  if (regno < FIRST_PSEUDO_REGISTER
+	      || regno <= LAST_VIRTUAL_REGISTER)
+	    {
+	      read_name (&name); // FIXME
+	      if (0)
+		fprintf (stderr, "FIXME: 'r': extra string `%s'\n",
+			 name.string);
+	    }
+	  int ch = read_skip_spaces ();
+	  /* Parse extra stuff at end of 'r'.
+	     We may have zero, one, or two sections marked by square
+	     brackets.  */
+	  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
+  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 +1872,147 @@ 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;
+  /* FIXME: */
+
+  /* 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 +2020,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..f6a7a27 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3641,7 +3641,11 @@ 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);
+extern void fixup_insn_refs (void (*cb) (location_t, rtx, int, int));
 
 /* In alias.c */
 extern rtx canon_rtx (rtx);
@@ -3746,5 +3750,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/TODO.rst b/gcc/rtl/TODO.rst
new file mode 100644
index 0000000..e6650be
--- /dev/null
+++ b/gcc/rtl/TODO.rst
@@ -0,0 +1,16 @@
+DONE
+====
+
+* driver support, to automatically invoke ``rtl1``
+
+TODO
+====
+
+* have it actually load RTL files
+
+* have it compile them
+
+* testsuite:
+
+  * gcc/testsuite/rtl.dg
+
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..54d5aff
--- /dev/null
+++ b/gcc/rtl/lang.opt
@@ -0,0 +1,36 @@
+; 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
+FIXME
+
+fsingle-pass=
+RTL Joined RejectNegative
+FIXME
+
+; 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..f91ad0d
--- /dev/null
+++ b/gcc/rtl/notes.rst
@@ -0,0 +1,131 @@
+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.
+
+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
+-----------
+
+* 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.
+
+* 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``).
+
+* 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.
+  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).
+
+* It's a work-in-progress.  There will be bugs.
+
+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?
diff --git a/gcc/rtl/rtl-errors.c b/gcc/rtl/rtl-errors.c
new file mode 100644
index 0000000..106295f
--- /dev/null
+++ b/gcc/rtl/rtl-errors.c
@@ -0,0 +1,32 @@
+/* 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"
+
+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..d0ed693
--- /dev/null
+++ b/gcc/rtl/rtl-frontend.c
@@ -0,0 +1,1257 @@
+/* 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.  */
+
+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;
+}
+
+/* The option mask.  */
+
+static unsigned int
+rtl_langhook_option_lang_mask (void)
+{
+  return CL_RTL;
+}
+
+/* Initialize the options structure.  */
+
+static void
+rtl_langhook_init_options_struct (struct gcc_options */*opts*/)
+{
+#if 0
+  /* Go says that signed overflow is precisely defined.  */
+  opts->x_flag_wrapv = 1;
+
+  /* We default to using strict aliasing, since Go pointers are safe.
+     This is turned off for code that imports the "unsafe" package,
+     because using unsafe.pointer violates C style aliasing
+     requirements.  */
+  opts->x_flag_strict_aliasing = 1;
+
+  /* Default to avoiding range issues for complex multiply and
+     divide.  */
+  opts->x_flag_complex_method = 2;
+
+  /* The builtin math functions should not set errno.  */
+  opts->x_flag_errno_math = 0;
+  opts->frontend_set_flag_errno_math = true;
+
+  /* Exceptions are used to handle recovering from panics.  */
+  opts->x_flag_exceptions = 1;
+  opts->x_flag_non_call_exceptions = 1;
+
+  /* We need to keep pointers live for the garbage collector.  */
+  opts->x_flag_keep_gc_roots_live = 1;
+
+  /* Go programs expect runtime.Callers to work, and that uses
+     libbacktrace that uses debug info.  Set the debug info level to 1
+     by default.  In post_options we will set the debug type if the
+     debug info level was not set back to 0 on the command line.  */
+  opts->x_debug_info_level = DINFO_LEVEL_TERSE;
+#endif
+}
+
+static const char *roundtrip_filename = NULL;
+static const char *single_pass_name = NULL;
+
+static bool
+rtl_langhook_handle_option (
+    size_t scode ATTRIBUTE_UNUSED,
+    const char *arg ATTRIBUTE_UNUSED,
+    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;
+
+class fixup
+{
+ public:
+  fixup (file_location loc, rtx insn)
+    : m_loc (loc), m_insn (insn)
+  {}
+  virtual ~fixup () {}
+
+  virtual void apply (function_reader *reader) const = 0;
+
+ protected:
+  file_location m_loc;
+  rtx m_insn;
+};
+
+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;
+};
+
+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;
+};
+
+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;
+};
+
+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;
+};
+
+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;
+};
+
+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;
+};
+
+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;
+};
+
+class function_reader : public rtx_reader
+{
+ public:
+  function_reader (line_maps *set);
+  ~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;
+};
+
+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;
+    }
+}
+
+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_insn, m_operand_idx) = *insn_from_uid;
+  else
+    {
+      const char *op_name = get_operand_name (m_insn, m_operand_idx);
+      if (op_name)
+	error_at (m_loc,
+		  "insn with UID %i not found for operand %i (%qs) of insn %i",
+		  m_insn_uid, m_operand_idx, op_name, INSN_UID (m_insn));
+      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_insn));
+    }
+}
+
+void
+fixup_bb::apply (function_reader */*reader*/) const
+{
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
+  gcc_assert (bb);
+  XBBDEF (m_insn, m_operand_idx) = bb;
+
+  rtx_insn *insn = as_a <rtx_insn *> (m_insn);
+  if (!BB_HEAD (bb))
+    BB_HEAD (bb) = insn;
+  BB_END (bb) = insn;
+}
+
+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_insn) = bb;
+}
+
+void
+fixup_source_location::apply (function_reader */*reader*/) const
+{
+  INSN_LOCATION (as_a <rtx_insn *> (m_insn)) = m_dloc->m_srcloc;
+}
+
+void
+fixup_jump_label::apply (function_reader *reader) const
+{
+  //inform (m_loc, "jump_label: %qs", m_label);
+  if (0 == strcmp (m_label, "return"))
+    JUMP_LABEL (m_insn) = ret_rtx;
+  else if (0 == strcmp (m_label, "simple_return"))
+    JUMP_LABEL (m_insn) = 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_insn) = *insn_from_uid;
+      else
+	error_at (m_loc,
+		  "insn with UID %i not found for operand %i (%qs) of insn %i",
+		  label_uid, m_operand_idx, "JUMP_LABEL", INSN_UID (m_insn));
+    }
+}
+
+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;
+}
+
+void
+fixup_expr::apply (function_reader *reader) const
+{
+  //inform (m_loc, "fixup_expr::apply: %qs", m_desc);
+  tree expr = reader->parse_mem_expr (m_desc);
+  switch (GET_CODE (m_insn))
+    {
+    case REG:
+      set_reg_attrs_for_decl_rtl (expr, m_insn);
+      break;
+    case MEM:
+      set_mem_expr (m_insn, expr);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  /* FIXME: not actually an insn. */
+}
+
+/* class function_reader : public rtx_reader */
+
+function_reader::function_reader (line_maps *set) : rtx_reader (set),
+    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::~function_reader ()
+{
+  int i;
+  fixup *f;
+  FOR_EACH_VEC_ELT (m_fixups, i, f)
+    delete f;
+}
+
+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);
+    }
+  int c = read_char ();
+  location_t end_loc = get_current_location ();
+  unread_char (c);
+  location_t insn_loc = make_location (start_loc, start_loc, end_loc);
+  if (0)
+    {
+      inform (insn_loc, "input insn");
+      debug (insn);
+    }
+  m_insns_by_uid.put (INSN_UID (insn), insn);
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+void
+function_reader::create_function ()
+{
+#if 0
+  cfg_layout_rtl_register_cfg_hooks ();
+#else
+  /* Currently we assume cfgrtl mode, rather than cfglayout mode.  */
+  rtl_register_cfg_hooks ();
+#endif
+
+  /* TODO: create cfun.  */
+  // how is the function created? step through how C frontend creates it
+  /* example was: "int test_1 (int i, int j, int k)" */
+  tree fn_name = get_identifier ("test_1"); /* FIXME.  */
+  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);
+
+  //struct function *fn = ; // DECL_STRUCT_FUNCTION (node->decl);
+  //push_cfun (fn);
+
+  create_cfg_and_basic_blocks ();
+  cfun->curr_properties = (PROP_cfg | PROP_rtl);
+
+  //pop_cfun ();
+
+  /* Do we need this to force cgraphunit.c to output the function? */
+  DECL_EXTERNAL (fndecl) = 0;
+  DECL_PRESERVE_P (fndecl) = 1;
+
+  #if 0
+      DECL_INITIAL (m_inner_fndecl) = m_inner_block;
+
+      /* how to add to function? the following appears to be how to
+	 set the body of a m_inner_fndecl: */
+      DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
+
+      /* Ensure that locals appear in the debuginfo.  */
+      BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
+
+      //debug_tree (m_inner_fndecl);
+#endif
+
+  /* Add to cgraph.  */
+  cgraph_node::add_new_function (fndecl, true /*lowered*/);
+
+  current_function_decl = NULL;
+}
+
+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);
+}
+
+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.  */
+#if 1
+  init_empty_tree_cfg_for_function (cfun);
+#else
+  init_flow (cfun);
+#endif
+
+  /* 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);
+      //df_bb_refs_record (bb->index, false);
+      //update_bb_for_insn (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;
+}
+
+/* FIXME.  */
+
+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)
+{
+  /* TODO: edges for jump.  */
+  /* FIXME: how to do this?  there could be multiple labels
+     e.g. computed jump.  */
+
+  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 ();
+}
+
+/* FIXME.  */
+
+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);
+}
+
+/* FIXME.  */
+
+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 ("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 ();
+
+  //regstat_init_n_sets_and_refs ();
+
+  /* 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);
+}
+
+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 (line_table);
+  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 ("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);
+}
+
+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;
+}
+
+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;
+}
+
+/* Record a builtin function.  We just ignore builtin functions.  */
+
+static tree
+rtl_langhook_builtin_function (tree decl)
+{
+  return decl;
+}
+
+/* Return true if we are in the global binding level.  */
+
+static bool
+rtl_langhook_global_bindings_p (void)
+{
+  return current_function_decl == NULL_TREE;
+}
+
+/* Push a declaration into the current binding level.  We can't
+   usefully implement this since we don't want to convert from tree
+   back to one of our internal data structures.  I think the only way
+   this is used is to record a decl which is to be returned by
+   getdecls, and we could implement it for that purpose if
+   necessary.  */
+
+static tree
+rtl_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+/* This hook is used to get the current list of declarations as trees.
+   We don't support that; instead we use the write_globals hook.  This
+   can't simply crash because it is called by -gstabs.  */
+
+static tree
+rtl_langhook_getdecls (void)
+{
+  return NULL;
+}
+
+/* Go specific gimplification.  We need to gimplify
+   CALL_EXPR_STATIC_CHAIN, because the gimplifier doesn't handle
+   it.  */
+
+static int
+rtl_langhook_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
+{
+  if (TREE_CODE (*expr_p) == CALL_EXPR
+      && CALL_EXPR_STATIC_CHAIN (*expr_p) != NULL_TREE)
+    gimplify_expr (&CALL_EXPR_STATIC_CHAIN (*expr_p), pre_p, post_p,
+		   is_gimple_val, fb_rvalue);
+  return GS_UNHANDLED;
+}
+
+#if 0
+/* Return a decl for the exception personality function.  The function
+   itself is implemented in libgo/runtime/go-unwind.c.  */
+
+static tree
+rtl_langhook_eh_personality (void)
+{
+  static tree personality_decl;
+  if (personality_decl == NULL_TREE)
+    {
+      personality_decl = build_personality_function ("gccgo");
+      rtl_preserve_from_gc (personality_decl);
+    }
+  return personality_decl;
+}
+#endif
+
+/* Functions called directly by the generic backend.  */
+
+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 ();
+}
+
+/* FIXME: This is a hack to preserve trees that we create from the
+   garbage collector.  */
+
+static GTY(()) tree rtl_gc_root;
+
+void
+rtl_preserve_from_gc (tree t)
+{
+  rtl_gc_root = tree_cons (NULL_TREE, t, rtl_gc_root);
+}
+
+/* Convert an identifier for use in an error message.  */
+
+const char *
+rtl_localize_identifier (const char *ident)
+{
+  return identifier_to_locale (ident);
+}
+
+#undef LANG_HOOKS_NAME
+#undef LANG_HOOKS_INIT
+#undef LANG_HOOKS_OPTION_LANG_MASK
+#undef LANG_HOOKS_INIT_OPTIONS_STRUCT
+#undef LANG_HOOKS_HANDLE_OPTION
+//#undef LANG_HOOKS_POST_OPTIONS
+#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
+#undef LANG_HOOKS_GIMPLIFY_EXPR
+//#undef LANG_HOOKS_EH_PERSONALITY
+
+#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_INIT_OPTIONS_STRUCT	rtl_langhook_init_options_struct
+#define LANG_HOOKS_HANDLE_OPTION	rtl_langhook_handle_option
+//#define LANG_HOOKS_POST_OPTIONS		rtl_langhook_post_options
+#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
+#define LANG_HOOKS_GIMPLIFY_EXPR	rtl_langhook_gimplify_expr
+//#define LANG_HOOKS_EH_PERSONALITY	rtl_langhook_eh_personality
+
+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..8652d35
--- /dev/null
+++ b/gcc/testsuite/lib/rtl-dg.exp
@@ -0,0 +1,59 @@
+#   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 } {
+    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/bad-include.rtl b/gcc/testsuite/rtl.dg/bad-include.rtl
new file mode 100644
index 0000000..5bd1580
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/bad-include.rtl
@@ -0,0 +1,5 @@
+/* Verify that we get sane error messages if errors occur in
+   an included file.
+   We give the included file a .md suffix to avoid it being
+   run by rtl.exp.  */
+(include "bad-includee.md")
diff --git a/gcc/testsuite/rtl.dg/bad-includee.md b/gcc/testsuite/rtl.dg/bad-includee.md
new file mode 100644
index 0000000..907b378
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/bad-includee.md
@@ -0,0 +1,5 @@
+(not-a-valid-kind-of-insn 1 0 0) /* { dg-error "unknown rtx code" } */
+/* { dg-begin-multiline-output "" }
+ (not-a-valid-kind-of-insn 1 0 0)
+                          ^
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/rtl.dg/dfinit.rtl b/gcc/testsuite/rtl.dg/dfinit.rtl
new file mode 100644
index 0000000..e885e1e
--- /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-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.c:7 -1
+     (nil))
+(insn 27 26 0 5 (use (reg/i:SI 0 ax)) ../../src/test-loop.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..1872ce3
--- /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-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.c:7 -1
+     (nil))
+(jump_insn:TI 34 23 33 2 (simple_return) ../../src/test-loop.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..f68f6c0
--- /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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/test-loop.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..6bd3fa6
--- /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-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.c:7 -1
+     (nil))
+(insn 27 26 0 5 (use (reg/i:SI 0 ax)) ../../src/test-loop.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..441f929
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/missing-include.rtl
@@ -0,0 +1,5 @@
+(include "does-not-exist.rtl") /* { dg-error "include file .does-not-exist.rtl. not found" } */
+/* { dg-begin-multiline-output "" }
+ (include "does-not-exist.rtl")
+ ^
+   { dg-end-multiline-output "" } */
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..21d9701
--- /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-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.c:4 -1
+     (nil))
+(insn 23 29 30 2 (use (reg/i:SI 0 ax)) ../../src/test-loop.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..faa88fb
--- /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/test-loop.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..a3eed17
--- /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/test-loop.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..3b91b32
--- /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/test-loop.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..7a1d0e1
--- /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/test-loop.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..97b565a
--- /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/test-loop.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..5666e17
--- /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/test-loop.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..2bf775f
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/roundtrip/roundtrip.exp
@@ -0,0 +1,82 @@
+# 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
+}
+
+# FIXME
+
+proc verify-roundtrip { input_file output_file } {
+    verbose "rtl-dg-test:" 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:
+
+proc rtl-dg-test { prog do_what extra_tool_flags } {
+    verbose "rtl-dg-test:" 3
+    verbose "  prog: $prog" 3
+    verbose "  do_what: $do_what" 3
+    verbose "  extra_tool_flags: $extra_tool_flags" 3
+    # TODO: better output_file name
+    set output_file /tmp/FIXME-roundtrip.rtl
+    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-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 "tests: $tests" 1
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_RTLFLAGS
+
+# 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..2ea3fdc
--- /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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/test-loop.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..ae0165f
--- /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 "tests: $tests" 1
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_RTLFLAGS
+
+# All done.
+dg-finish
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..b5dae35
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/unknown-insn-uid.rtl
@@ -0,0 +1,11 @@
+(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" }
+/* { dg-begin-multiline-output "" }
+ (note 6 1 0 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+         ^
+   { dg-end-multiline-output "" } */
+
+(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" }
+/* { dg-begin-multiline-output "" }
+ (note 7 0 3 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+           ^
+   { dg-end-multiline-output "" } */
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..173c172
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/unknown-rtx-code.rtl
@@ -0,0 +1,5 @@
+(not-a-valid-kind-of-insn 1 0 0) ;; { dg-error "unknown rtx code" }
+/* { dg-begin-multiline-output "" }
+ (not-a-valid-kind-of-insn 1 0 0)
+                          ^
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/rtl.dg/vregs.rtl b/gcc/testsuite/rtl.dg/vregs.rtl
new file mode 100644
index 0000000..b850ab3
--- /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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.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/test-loop.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/test-loop.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 f133abc..36feb47 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));
diff --git a/test-loop.c b/test-loop.c
new file mode 100644
index 0000000..ebb8aef
--- /dev/null
+++ b/test-loop.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;
+}
-- 
1.8.5.3

