From 8549a48f77784676d2b87c4aa9634a7e6423c800 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 11 May 2016 13:57:24 -0400
Subject: [PATCH 06/23] FIXME: move rtl function reading into a new
 gcc/read-rtl-function.c

---
 gcc/read-md.h           |   3 +
 gcc/read-rtl-function.c | 812 ++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/rtl/Make-lang.in    |   3 +-
 gcc/rtl/rtl-frontend.c  | 749 +-------------------------------------------
 4 files changed, 819 insertions(+), 748 deletions(-)
 create mode 100644 gcc/read-rtl-function.c

diff --git a/gcc/read-md.h b/gcc/read-md.h
index 342a716..6590934 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -245,4 +245,7 @@ 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_rtl_function_body (int argc, const char **argv,
+				    bool (*parse_opt) (const char *));
+
 #endif /* GCC_READ_MD_H */
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
new file mode 100644
index 0000000..3292818
--- /dev/null
+++ b/gcc/read-rtl-function.c
@@ -0,0 +1,812 @@
+/* read-rtl-function.c - Reader for RTL function dumps
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "stor-layout.h"
+#include "debug.h"
+#include "convert.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "common/common-target.h"
+#include "read-md.h"
+#include <mpfr.h>
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "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"
+
+class function_reader;
+
+/* Abstract base class for recording post-processing steps that must be
+   done after reading a .rtl file.  */
+
+class fixup
+{
+ public:
+  fixup (file_location loc, rtx x)
+    : m_loc (loc), m_rtx (x)
+  {}
+  virtual ~fixup () {}
+
+  virtual void apply (function_reader *reader) const = 0;
+
+ protected:
+  file_location m_loc;
+  rtx m_rtx;
+};
+
+/* An abstract subclass of fixup for post-processing steps that
+   act on a specific operand of a specific instruction.  */
+
+class operand_fixup : public fixup
+{
+ public:
+  operand_fixup (file_location loc, rtx insn, int operand_idx)
+    : fixup (loc, insn), m_operand_idx (operand_idx)
+  {}
+
+ protected:
+  int m_operand_idx;
+};
+
+/* A concrete subclass of operand_fixup: fixup an rtx_insn *
+   field (NEXT_INSN/PREV_INSN) based on an integer UID.  */
+
+class fixup_insn_uid : public operand_fixup
+{
+ public:
+  fixup_insn_uid (file_location loc, rtx insn, int operand_idx, int insn_uid)
+    : operand_fixup (loc, insn, operand_idx),
+      m_insn_uid (insn_uid)
+  {}
+
+  void apply (function_reader *reader) const;
+
+ private:
+  int m_insn_uid;
+};
+
+/* A concrete subclass of operand_fixup: fix up a basic_block
+   pointer field based on an integer block ID.  */
+
+class fixup_bb : public operand_fixup
+{
+ public:
+  fixup_bb (file_location loc, rtx insn, int operand_idx, int bb_idx)
+    : operand_fixup (loc, insn, operand_idx),
+      m_bb_idx (bb_idx)
+  {}
+
+  void apply (function_reader *reader) const;
+
+ private:
+  int m_bb_idx;
+};
+
+/* A concrete subclass of operand_fixup: fix up a
+   NOTE_INSN_BASIC_BLOCK based on an integer block ID.  */
+
+class fixup_note_insn_basic_block : public operand_fixup
+{
+ public:
+  fixup_note_insn_basic_block (file_location loc, rtx insn, int operand_idx,
+			       int bb_idx)
+    : operand_fixup (loc, insn, operand_idx),
+      m_bb_idx (bb_idx)
+  {}
+
+  void apply (function_reader *reader) const;
+
+ private:
+  int m_bb_idx;
+};
+
+/* A concrete subclass of operand_fixup: fix up the INSN_LOCATION
+   of the insn based on a deferred_location *.  */
+
+class fixup_source_location : public operand_fixup
+{
+ public:
+  fixup_source_location (file_location loc, rtx insn,
+			 int operand_idx,
+			 deferred_location *dloc)
+    : operand_fixup (loc, insn, operand_idx),
+      m_dloc (dloc)
+  {}
+
+  void apply (function_reader *reader) const;
+
+ private:
+  deferred_location *m_dloc;
+};
+
+/* A concrete subclass of operand_fixup: fix up the JUMP_LABEL
+   of an insn based on a label name.  */
+
+class fixup_jump_label : public operand_fixup
+{
+ public:
+  fixup_jump_label (file_location loc, rtx insn,
+		    int operand_idx,
+		    const char *label)
+    : operand_fixup (loc, insn, operand_idx),
+      m_label (xstrdup (label))
+  {}
+
+  void apply (function_reader *reader) const;
+
+ private:
+  const char *m_label;
+};
+
+/* A concrete subclass of fixup (not operand_fixup): fix up
+   the expr of an rtx (REG or MEM) based on a textual dump.  */
+
+class fixup_expr : public fixup
+{
+ public:
+  fixup_expr (file_location loc, rtx x, const char *desc)
+    : fixup (loc, x),
+      m_desc (xstrdup (desc))
+  {}
+
+  void apply (function_reader *reader) const;
+
+ private:
+  char *m_desc;
+};
+
+/* Subclass of rtx_reader for reading function dumps.  */
+
+class function_reader : public rtx_reader
+{
+ public:
+  function_reader ();
+  ~function_reader ();
+
+  void handle_unknown_directive (file_location, const char *);
+
+  void add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+			   int insn_uid);
+
+  void add_fixup_bb (file_location loc, rtx insn,
+		     int operand_idx, int bb_idx);
+
+  void add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+					int operand_idx, int bb_idx);
+
+  void add_fixup_source_location (file_location loc, rtx insn,
+				  int operand_idx,
+				  const char *filename, int lineno);
+
+  void add_fixup_jump_label (file_location loc, rtx insn,
+			     int operand_idx,
+			     const char *label);
+
+  void add_fixup_expr (file_location loc, rtx x,
+		       const char *desc);
+
+  void create_function ();
+  void apply_fixups ();
+  void create_cfg_edges ();
+
+  rtx_insn **get_insn_by_uid (int uid);
+
+  rtx_insn *get_first_insn () const { return m_first_insn; }
+
+  tree parse_mem_expr (const char *desc);
+
+ private:
+  void create_cfg_and_basic_blocks ();
+
+ private:
+  struct uid_hash : int_hash <int, -1, -2> {};
+  hash_map<uid_hash, rtx_insn *> m_insns_by_uid;
+  auto_vec<fixup *> m_fixups;
+  bitmap_head m_bb_indices;
+  rtx_insn *m_first_insn;
+  deferred_locations m_deferred_locations;
+  auto_vec<tree> m_fake_scope;
+};
+
+/* Return a textual description of the given operand of the given rtx.  */
+
+static const char *
+get_operand_name (rtx insn, int operand_idx)
+{
+  gcc_assert (is_a <rtx_insn *> (insn));
+  switch (operand_idx)
+    {
+    case 0:
+      return "PREV_INSN";
+    case 1:
+      return "NEXT_INSN";
+    default:
+      return NULL;
+    }
+}
+
+/* Fixup an rtx_insn * field (NEXT_INSN/PREV_INSN) based on an integer
+   UID.  */
+
+void
+fixup_insn_uid::apply (function_reader *reader) const
+{
+  rtx_insn **insn_from_uid = reader->get_insn_by_uid (m_insn_uid);
+  if (insn_from_uid)
+    XEXP (m_rtx, m_operand_idx) = *insn_from_uid;
+  else
+    {
+      const char *op_name = get_operand_name (m_rtx, m_operand_idx);
+      if (op_name)
+	error_at (m_loc,
+		  "insn with UID %i not found for operand %i (`%s') of insn %i",
+		  m_insn_uid, m_operand_idx, op_name, INSN_UID (m_rtx));
+      else
+	error_at (m_loc,
+		  "insn with UID %i not found for operand %i of insn %i",
+		  m_insn_uid, m_operand_idx, INSN_UID (m_rtx));
+    }
+}
+
+/* Fix up a basic_block pointer field based on an integer block ID.
+   Update BB_HEAD and BB_END of the block as appropriate, as if the insn
+   was being added to the end of the block.  */
+
+void
+fixup_bb::apply (function_reader */*reader*/) const
+{
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
+  gcc_assert (bb);
+  XBBDEF (m_rtx, m_operand_idx) = bb;
+
+  rtx_insn *insn = as_a <rtx_insn *> (m_rtx);
+  if (!BB_HEAD (bb))
+    BB_HEAD (bb) = insn;
+  BB_END (bb) = insn;
+}
+
+/* Fix up a NOTE_INSN_BASIC_BLOCK based on an integer block ID.  */
+
+void
+fixup_note_insn_basic_block::apply (function_reader */*reader*/) const
+{
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
+  gcc_assert (bb);
+  NOTE_BASIC_BLOCK (m_rtx) = bb;
+}
+
+/* Fix up the INSN_LOCATION of the insn based on a deferred_location *.  */
+
+void
+fixup_source_location::apply (function_reader */*reader*/) const
+{
+  INSN_LOCATION (as_a <rtx_insn *> (m_rtx)) = m_dloc->m_srcloc;
+}
+
+/* Fix up the JUMP_LABEL of an insn based on a label name.  */
+
+void
+fixup_jump_label::apply (function_reader *reader) const
+{
+  if (0 == strcmp (m_label, "return"))
+    JUMP_LABEL (m_rtx) = ret_rtx;
+  else if (0 == strcmp (m_label, "simple_return"))
+    JUMP_LABEL (m_rtx) = simple_return_rtx;
+  else
+    {
+      int label_uid = atoi (m_label);
+      rtx_insn **insn_from_uid = reader->get_insn_by_uid (label_uid);
+      if (insn_from_uid)
+	JUMP_LABEL (m_rtx) = *insn_from_uid;
+      else
+	error_at (m_loc,
+		  "insn with UID %i not found for operand %i (`%s') of insn %i",
+		  label_uid, m_operand_idx, "JUMP_LABEL", INSN_UID (m_rtx));
+    }
+}
+
+/* Parse a tree dump for MEM_EXPR and turn it back into a tree.
+   We handle "<retval>", but for anything else we "cheat" by building a
+   global VAR_DECL of type "int" with that name (returning the same global
+   for a name if we see the same name more than once).  */
+
+tree
+function_reader::parse_mem_expr (const char *desc)
+{
+  if (0 == strcmp (desc, "<retval>"))
+    {
+      tree fndecl = cfun->decl;
+      return DECL_RESULT (fndecl);
+    }
+
+  /* FIXME: use a hash rather than linear search.  */
+  int i;
+  tree t;
+  FOR_EACH_VEC_ELT (m_fake_scope, i, t)
+    if (0 == strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (t))))
+      return t;
+
+  /* Not found?  Create it.
+     This allows mimicing of real data but avoids having to specify
+     e.g. names of locals, params etc.
+     Though this way we don't know if we have a PARM_DECL vs a VAR_DECL,
+     and we don't know the types.  Fake it by making everything be
+     a VAR_DECL of "int" type.  */
+  t = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		  get_identifier (desc),
+		  integer_type_node);
+  m_fake_scope.safe_push (t);
+  return t;
+}
+
+/* Fix up the expr of an rtx (REG or MEM) based on a textual dump.  */
+
+void
+fixup_expr::apply (function_reader *reader) const
+{
+  tree expr = reader->parse_mem_expr (m_desc);
+  switch (GET_CODE (m_rtx))
+    {
+    case REG:
+      set_reg_attrs_for_decl_rtl (expr, m_rtx);
+      break;
+    case MEM:
+      set_mem_expr (m_rtx, expr);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* class function_reader : public rtx_reader */
+
+/* function_reader's constructor.  */
+
+function_reader::function_reader () : rtx_reader (),
+    m_first_insn (NULL)
+{
+  bitmap_initialize (&m_bb_indices, NULL);
+  bitmap_set_bit (&m_bb_indices, ENTRY_BLOCK);
+  bitmap_set_bit (&m_bb_indices, EXIT_BLOCK);
+}
+
+/* function_reader's destructor.  */
+
+function_reader::~function_reader ()
+{
+  int i;
+  fixup *f;
+  FOR_EACH_VEC_ELT (m_fixups, i, f)
+    delete f;
+}
+
+/* Implementation of rtx_reader::handle_unknown_directive.
+   Parse rtx instructions by calling read_rtx_code, calling
+   set_first_insn and set_last_insn as appropriate.  */
+
+void
+function_reader::handle_unknown_directive (file_location /*start_loc*/,
+					   const char *name)
+{
+  rtx x = read_rtx_code (name);
+  if (!x)
+    return;
+  rtx_insn *insn = as_a <rtx_insn *> (x);
+  set_last_insn (insn);
+  if (!m_first_insn)
+    {
+      m_first_insn = insn;
+      set_first_insn (insn);
+    }
+  m_insns_by_uid.put (INSN_UID (insn), insn);
+}
+
+/* Implementation of rtx_reader::add_fixup_insn_uid.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+				     int insn_uid)
+{
+  m_fixups.safe_push (new fixup_insn_uid (loc, insn, operand_idx, insn_uid));
+}
+
+/* Implementation of rtx_reader::add_fixup_bb.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_bb (file_location loc, rtx insn, int operand_idx,
+			       int bb_idx)
+{
+  bitmap_set_bit (&m_bb_indices, bb_idx);
+  m_fixups.safe_push (new fixup_bb (loc, insn, operand_idx, bb_idx));
+}
+
+/* Implementation of rtx_reader::add_fixup_note_insn_basic_block.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+						  int operand_idx, int bb_idx)
+{
+  m_fixups.safe_push (new fixup_note_insn_basic_block (loc, insn, operand_idx,
+						       bb_idx));
+}
+
+/* Implementation of rtx_reader::add_fixup_source_location.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_source_location (file_location loc, rtx insn,
+					    int operand_idx,
+					    const char *filename, int lineno)
+{
+  source_file *file = m_deferred_locations.get_source_file (filename);
+  source_line *line = file->get_source_line (lineno);
+  deferred_location *dloc = line->get_location (NULL, 0);
+  m_fixups.safe_push (new fixup_source_location (loc, insn, operand_idx, dloc));
+}
+
+/* Implementation of rtx_reader::add_fixup_jump_label.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_jump_label (file_location loc, rtx insn,
+				       int operand_idx,
+				       const char *label)
+{
+  m_fixups.safe_push (new fixup_jump_label (loc, insn, operand_idx, label));
+}
+
+/* Implementation of rtx_reader::add_fixup_expr.
+   Record the information for later post-processing.  */
+
+void
+function_reader::add_fixup_expr (file_location loc, rtx insn,
+				 const char *desc)
+{
+  gcc_assert (desc);
+  /* Fail early if the RTL reader erroneously hands us an int.  */
+  gcc_assert (!ISDIGIT (desc[0]));
+
+  m_fixups.safe_push (new fixup_expr (loc, insn, desc));
+}
+
+/* Set up state for the function *before* fixups are applied.
+
+   Create "cfun" and a decl for the function.
+   For the moment, every function decl is hardcoded as
+      int test_1 (int i, int j, int k);
+   Set up various other state:
+   - state set up by expand_function_start (e.g. crtl->return_rtx).
+   - the cfg and basic blocks (edges are created later, *after* fixups
+   are applied).
+   - add the function to the callgraph.  */
+
+void
+function_reader::create_function ()
+{
+  /* Currently we assume cfgrtl mode, rather than cfglayout mode.  */
+  if (0)
+    cfg_layout_rtl_register_cfg_hooks ();
+  else
+    rtl_register_cfg_hooks ();
+
+  /* Create cfun.  */
+  tree fn_name = get_identifier ("test_1");
+  tree int_type = integer_type_node;
+  tree return_type = int_type;
+  tree arg_types[3] = {int_type, int_type, int_type};
+  tree fn_type = build_function_type_array (return_type, 3, arg_types);
+  tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+				 fn_type);
+  tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+			     return_type);
+  DECL_ARTIFICIAL (resdecl) = 1;
+  DECL_IGNORED_P (resdecl) = 1;
+  DECL_RESULT (fndecl) = resdecl;
+  allocate_struct_function (fndecl, false);
+  /* This sets cfun.  */
+
+  /* Normally, various state gets set up by expand_function_start, e.g.
+     crtl->return_rtx, based on DECL_RESULT (fndecl).
+     We call it here to ensure the state is set up, with emit_insns as
+     false, so no new instructions are emitted.  */
+  current_function_decl = fndecl;
+  expand_function_start (fndecl, false);
+
+  create_cfg_and_basic_blocks ();
+  cfun->curr_properties = (PROP_cfg | PROP_rtl);
+
+  /* Do we need this to force cgraphunit.c to output the function? */
+  DECL_EXTERNAL (fndecl) = 0;
+  DECL_PRESERVE_P (fndecl) = 1;
+
+  /* Add to cgraph.  */
+  cgraph_node::add_new_function (fndecl, true /*lowered*/);
+
+  current_function_decl = NULL;
+}
+
+/* Apply all of the recorded fixups.  */
+
+void
+function_reader::apply_fixups ()
+{
+  m_deferred_locations.add_to_line_table ();
+  /* line_table should now be populated; every deferred_location should
+     now have an m_srcloc.  */
+
+  int i;
+  fixup *f;
+  FOR_EACH_VEC_ELT (m_fixups, i, f)
+    f->apply (this);
+}
+
+/* Given a UID value, try to locate a pointer to the corresponding
+   rtx_insn *, or NULL if if can't be found.  */
+
+rtx_insn **
+function_reader::get_insn_by_uid (int uid)
+{
+  return m_insns_by_uid.get (uid);
+}
+
+/* Create cfun's CFG and populate with blocks, a helper
+   function for function_reader::create_function ().
+
+   The edges are created later on, after fixups are applied.
+
+   We can't call create_basic_block and use the regular RTL block-creation
+   hooks, since this creates NOTE_INSN_BASIC_BLOCK instances.  We don't
+   want to do that; we want to use the notes we were provided with.
+
+   The term "index" has two meanings for basic blocks in a CFG:
+   (a) the "index" field within struct basic_block_def.
+   (b) the index of a basic_block within the cfg's x_basic_block_info
+   vector, as accessed via BASIC_BLOCK_FOR_FN.
+
+   These can get out-of-sync when basic blocks are optimized away.
+   They get back in sync by "compact_blocks".
+   We make the assumption that the CFG has been compacted, and
+   so we reconstruct cfun->cfg->x_basic_block_info->m_vecdata with NULL
+   values in it for any missing basic blocks, so that (a) == (b) for
+   all of the blocks we create.  The doubly-linked list of basic
+   blocks (next_bb/prev_bb) skips over these "holes".  */
+
+void
+function_reader::create_cfg_and_basic_blocks ()
+{
+  /* Create bare-bones cfg.  This creates the entry and exit blocks.  */
+  init_empty_tree_cfg_for_function (cfun);
+
+  /* Ensure that the vector of basic_block pointers is big enough.  */
+  unsigned highest_bb_idx = bitmap_last_set_bit (&m_bb_indices);
+  size_t new_size = highest_bb_idx + 1;
+  if (basic_block_info_for_fn (cfun)->length () < new_size)
+    vec_safe_grow_cleared (basic_block_info_for_fn (cfun), new_size);
+
+  /* Populate the vector.  */
+  unsigned bb_idx;
+  bitmap_iterator bi;
+  basic_block after = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+  gcc_assert (after);
+  EXECUTE_IF_SET_IN_BITMAP (&m_bb_indices, 0, bb_idx, bi)
+    {
+      /* The entry and exit blocks were already created above.  */
+      if (bb_idx == ENTRY_BLOCK || bb_idx == EXIT_BLOCK)
+	{
+	  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_idx);
+	  init_rtl_bb_info (bb);
+	  continue;
+	}
+      basic_block bb = alloc_block ();
+      init_rtl_bb_info (bb);
+      bb->index = bb_idx;
+      bb->flags = BB_NEW | BB_RTL;
+      link_block (bb, after);
+
+      n_basic_blocks_for_fn (cfun)++;
+      SET_BASIC_BLOCK_FOR_FN (cfun, bb_idx, bb);
+      BB_SET_PARTITION (bb, BB_UNPARTITIONED);
+
+      /* Tag the block so that we know it has been used when considering
+	 other basic block notes.  */
+      bb->aux = bb;
+
+      after = bb;
+    }
+
+  last_basic_block_for_fn (cfun) = highest_bb_idx + 1;
+}
+
+/* Visit every LABEL_REF within JUMP_INSN, calling CB on it, providing it
+   with USER_DATA.
+   FIXME: is there a preexisting way to do this?  */
+
+static void
+for_each_label_ref (rtx_jump_insn *jump_insn,
+		    void (*cb) (rtx_jump_insn *jump_insn,
+				rtx label_ref,
+				void *user_data),
+		    void *user_data)
+{
+  if (any_condjump_p (jump_insn))
+    {
+      rtx label_ref = condjump_label (jump_insn);
+      cb (jump_insn, label_ref, user_data);
+      return;
+    }
+
+  if (simplejump_p (jump_insn))
+    {
+      rtx label_ref = SET_SRC (PATTERN (jump_insn));
+      cb (jump_insn, label_ref, user_data);
+      return;
+    }
+
+  rtx_jump_table_data *tablep;
+  if (tablejump_p (jump_insn, NULL, &tablep))
+    {
+      gcc_assert (tablep);
+      rtvec labels = tablep->get_labels ();
+      int i, veclen = GET_NUM_ELEM (labels);
+      for (i = 0; i < veclen; ++i)
+	{
+	  rtx label_ref = RTVEC_ELT (labels, i);
+	  cb (jump_insn, label_ref, user_data);
+	}
+      return;
+    }
+
+  if (ANY_RETURN_P (PATTERN (jump_insn)))
+    return;
+
+  /* TODO: something else?  */
+  gcc_unreachable ();
+}
+
+/* Create an edge from SRC to DST, with the given flags.  */
+
+static void
+add_edge (basic_block src, basic_block dst, int flags)
+{
+  if (0)
+    fprintf (stderr, "making edge %i->%i\n",
+	     src->index, dst->index);
+  unchecked_make_edge (src, dst, flags);
+}
+
+/* Edge-creation callback for function_reader::create_cfg_edges.  */
+
+static void
+add_edge_cb (rtx_jump_insn *jump_insn, rtx label_ref, void */*user_data*/)
+{
+  gcc_assert (jump_insn);
+  gcc_assert (label_ref);
+  rtx_insn *label_insn = as_a <rtx_insn *> (LABEL_REF_LABEL (label_ref));
+  add_edge (BLOCK_FOR_INSN (jump_insn), BLOCK_FOR_INSN (label_insn), 0);
+}
+
+/* Create edges within cfun's CFG, by examining instructions in the
+   basic blocks and reconstructing the edges accordingly.
+   This is done after fixups are applied, since the latter is responsible
+   for setting up BB_HEAD and BB_END within each basic block.
+
+   This assumes cfgrtl mode, in which the edges are implicit from
+   the jump instructions.  It won't work for cfglayout mode, which
+   represents unconditional jumps purely as edges within the CFG,
+   without instructions, and this information isn't (currently)
+   written out to dumps.  */
+
+void
+function_reader::create_cfg_edges ()
+{
+  /* Create edge from ENTRY_BLOCK to block of first insn.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+  add_edge (entry, entry->next_bb, EDGE_FALLTHRU);
+
+  /* Create other edges.
+
+     The edge from the block of last insn to EXIT_BLOCK is created
+     below, by fall-through from the end of its block.  */
+  basic_block bb;
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      if (!BB_HEAD (bb))
+	continue;
+      rtx_insn *end_insn = BB_END (bb);
+      if (rtx_jump_insn *jump_insn = dyn_cast <rtx_jump_insn *> (end_insn))
+	{
+	  if (0)
+	    fprintf (stderr, "bb %i ends in jump\n", bb->index);
+	  if (!any_uncondjump_p (end_insn))
+	    {
+	      /* Add fallthrough edge first.  */
+	      gcc_assert (bb->next_bb);
+	      add_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+	    }
+	  for_each_label_ref (jump_insn, add_edge_cb, NULL);
+	}
+      else
+	{
+	  if (0)
+	    fprintf (stderr, "bb %i ends in non-jump\n", bb->index);
+	  if (bb->next_bb != NULL)
+	    {
+	      /* Add fallthrough edge.  */
+	      gcc_assert (bb->next_bb);
+	      add_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+	    }
+	}
+    }
+}
+
+bool
+read_rtl_function_body (int argc, const char **argv,
+			bool (*parse_opt) (const char *))
+{
+  function_reader reader;
+  if (!reader.read_md_files (argc, argv, parse_opt))
+    return false;
+
+  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 ();
+
+  return true;
+}
diff --git a/gcc/rtl/Make-lang.in b/gcc/rtl/Make-lang.in
index 8c913bc..45dea07 100644
--- a/gcc/rtl/Make-lang.in
+++ b/gcc/rtl/Make-lang.in
@@ -32,7 +32,8 @@ RTL_OBJS = \
 	rtl/rtl-errors.o \
 	rtl/rtl-frontend.o \
 	read-md.o \
-	read-rtl.o
+	read-rtl.o \
+	read-rtl-function.o
 
 rtl1$(exeext): $(RTL_OBJS) attribs.o $(BACKEND) $(LIBDEPS)
 	+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
diff --git a/gcc/rtl/rtl-frontend.c b/gcc/rtl/rtl-frontend.c
index 8ac22db3..5737cca 100644
--- a/gcc/rtl/rtl-frontend.c
+++ b/gcc/rtl/rtl-frontend.c
@@ -165,734 +165,6 @@ rtl_langhook_handle_option (
   return true;
 }
 
-class function_reader;
-
-/* Abstract base class for recording post-processing steps that must be
-   done after reading a .rtl file.  */
-
-class fixup
-{
- public:
-  fixup (file_location loc, rtx x)
-    : m_loc (loc), m_rtx (x)
-  {}
-  virtual ~fixup () {}
-
-  virtual void apply (function_reader *reader) const = 0;
-
- protected:
-  file_location m_loc;
-  rtx m_rtx;
-};
-
-/* An abstract subclass of fixup for post-processing steps that
-   act on a specific operand of a specific instruction.  */
-
-class operand_fixup : public fixup
-{
- public:
-  operand_fixup (file_location loc, rtx insn, int operand_idx)
-    : fixup (loc, insn), m_operand_idx (operand_idx)
-  {}
-
- protected:
-  int m_operand_idx;
-};
-
-/* A concrete subclass of operand_fixup: fixup an rtx_insn *
-   field (NEXT_INSN/PREV_INSN) based on an integer UID.  */
-
-class fixup_insn_uid : public operand_fixup
-{
- public:
-  fixup_insn_uid (file_location loc, rtx insn, int operand_idx, int insn_uid)
-    : operand_fixup (loc, insn, operand_idx),
-      m_insn_uid (insn_uid)
-  {}
-
-  void apply (function_reader *reader) const;
-
- private:
-  int m_insn_uid;
-};
-
-/* A concrete subclass of operand_fixup: fix up a basic_block
-   pointer field based on an integer block ID.  */
-
-class fixup_bb : public operand_fixup
-{
- public:
-  fixup_bb (file_location loc, rtx insn, int operand_idx, int bb_idx)
-    : operand_fixup (loc, insn, operand_idx),
-      m_bb_idx (bb_idx)
-  {}
-
-  void apply (function_reader *reader) const;
-
- private:
-  int m_bb_idx;
-};
-
-/* A concrete subclass of operand_fixup: fix up a
-   NOTE_INSN_BASIC_BLOCK based on an integer block ID.  */
-
-class fixup_note_insn_basic_block : public operand_fixup
-{
- public:
-  fixup_note_insn_basic_block (file_location loc, rtx insn, int operand_idx,
-			       int bb_idx)
-    : operand_fixup (loc, insn, operand_idx),
-      m_bb_idx (bb_idx)
-  {}
-
-  void apply (function_reader *reader) const;
-
- private:
-  int m_bb_idx;
-};
-
-/* A concrete subclass of operand_fixup: fix up the INSN_LOCATION
-   of the insn based on a deferred_location *.  */
-
-class fixup_source_location : public operand_fixup
-{
- public:
-  fixup_source_location (file_location loc, rtx insn,
-			 int operand_idx,
-			 deferred_location *dloc)
-    : operand_fixup (loc, insn, operand_idx),
-      m_dloc (dloc)
-  {}
-
-  void apply (function_reader *reader) const;
-
- private:
-  deferred_location *m_dloc;
-};
-
-/* A concrete subclass of operand_fixup: fix up the JUMP_LABEL
-   of an insn based on a label name.  */
-
-class fixup_jump_label : public operand_fixup
-{
- public:
-  fixup_jump_label (file_location loc, rtx insn,
-		    int operand_idx,
-		    const char *label)
-    : operand_fixup (loc, insn, operand_idx),
-      m_label (xstrdup (label))
-  {}
-
-  void apply (function_reader *reader) const;
-
- private:
-  const char *m_label;
-};
-
-/* A concrete subclass of fixup (not operand_fixup): fix up
-   the expr of an rtx (REG or MEM) based on a textual dump.  */
-
-class fixup_expr : public fixup
-{
- public:
-  fixup_expr (file_location loc, rtx x, const char *desc)
-    : fixup (loc, x),
-      m_desc (xstrdup (desc))
-  {}
-
-  void apply (function_reader *reader) const;
-
- private:
-  char *m_desc;
-};
-
-/* Subclass of rtx_reader for reading function dumps.  */
-
-class function_reader : public rtx_reader
-{
- public:
-  function_reader ();
-  ~function_reader ();
-
-  void handle_unknown_directive (file_location, const char *);
-
-  void add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
-			   int insn_uid);
-
-  void add_fixup_bb (file_location loc, rtx insn,
-		     int operand_idx, int bb_idx);
-
-  void add_fixup_note_insn_basic_block (file_location loc, rtx insn,
-					int operand_idx, int bb_idx);
-
-  void add_fixup_source_location (file_location loc, rtx insn,
-				  int operand_idx,
-				  const char *filename, int lineno);
-
-  void add_fixup_jump_label (file_location loc, rtx insn,
-			     int operand_idx,
-			     const char *label);
-
-  void add_fixup_expr (file_location loc, rtx x,
-		       const char *desc);
-
-  void create_function ();
-  void apply_fixups ();
-  void create_cfg_edges ();
-
-  rtx_insn **get_insn_by_uid (int uid);
-
-  rtx_insn *get_first_insn () const { return m_first_insn; }
-
-  tree parse_mem_expr (const char *desc);
-
- private:
-  void create_cfg_and_basic_blocks ();
-
- private:
-  struct uid_hash : int_hash <int, -1, -2> {};
-  hash_map<uid_hash, rtx_insn *> m_insns_by_uid;
-  auto_vec<fixup *> m_fixups;
-  bitmap_head m_bb_indices;
-  rtx_insn *m_first_insn;
-  deferred_locations m_deferred_locations;
-  auto_vec<tree> m_fake_scope;
-};
-
-/* Return a textual description of the given operand of the given rtx.  */
-
-static const char *
-get_operand_name (rtx insn, int operand_idx)
-{
-  gcc_assert (is_a <rtx_insn *> (insn));
-  switch (operand_idx)
-    {
-    case 0:
-      return "PREV_INSN";
-    case 1:
-      return "NEXT_INSN";
-    default:
-      return NULL;
-    }
-}
-
-/* Fixup an rtx_insn * field (NEXT_INSN/PREV_INSN) based on an integer
-   UID.  */
-
-void
-fixup_insn_uid::apply (function_reader *reader) const
-{
-  rtx_insn **insn_from_uid = reader->get_insn_by_uid (m_insn_uid);
-  if (insn_from_uid)
-    XEXP (m_rtx, m_operand_idx) = *insn_from_uid;
-  else
-    {
-      const char *op_name = get_operand_name (m_rtx, m_operand_idx);
-      if (op_name)
-	error_at (m_loc,
-		  "insn with UID %i not found for operand %i (`%s') of insn %i",
-		  m_insn_uid, m_operand_idx, op_name, INSN_UID (m_rtx));
-      else
-	error_at (m_loc,
-		  "insn with UID %i not found for operand %i of insn %i",
-		  m_insn_uid, m_operand_idx, INSN_UID (m_rtx));
-    }
-}
-
-/* Fix up a basic_block pointer field based on an integer block ID.
-   Update BB_HEAD and BB_END of the block as appropriate, as if the insn
-   was being added to the end of the block.  */
-
-void
-fixup_bb::apply (function_reader */*reader*/) const
-{
-  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
-  gcc_assert (bb);
-  XBBDEF (m_rtx, m_operand_idx) = bb;
-
-  rtx_insn *insn = as_a <rtx_insn *> (m_rtx);
-  if (!BB_HEAD (bb))
-    BB_HEAD (bb) = insn;
-  BB_END (bb) = insn;
-}
-
-/* Fix up a NOTE_INSN_BASIC_BLOCK based on an integer block ID.  */
-
-void
-fixup_note_insn_basic_block::apply (function_reader */*reader*/) const
-{
-  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
-  gcc_assert (bb);
-  NOTE_BASIC_BLOCK (m_rtx) = bb;
-}
-
-/* Fix up the INSN_LOCATION of the insn based on a deferred_location *.  */
-
-void
-fixup_source_location::apply (function_reader */*reader*/) const
-{
-  INSN_LOCATION (as_a <rtx_insn *> (m_rtx)) = m_dloc->m_srcloc;
-}
-
-/* Fix up the JUMP_LABEL of an insn based on a label name.  */
-
-void
-fixup_jump_label::apply (function_reader *reader) const
-{
-  if (0 == strcmp (m_label, "return"))
-    JUMP_LABEL (m_rtx) = ret_rtx;
-  else if (0 == strcmp (m_label, "simple_return"))
-    JUMP_LABEL (m_rtx) = simple_return_rtx;
-  else
-    {
-      int label_uid = atoi (m_label);
-      rtx_insn **insn_from_uid = reader->get_insn_by_uid (label_uid);
-      if (insn_from_uid)
-	JUMP_LABEL (m_rtx) = *insn_from_uid;
-      else
-	error_at (m_loc,
-		  "insn with UID %i not found for operand %i (`%s') of insn %i",
-		  label_uid, m_operand_idx, "JUMP_LABEL", INSN_UID (m_rtx));
-    }
-}
-
-/* Parse a tree dump for MEM_EXPR and turn it back into a tree.
-   We handle "<retval>", but for anything else we "cheat" by building a
-   global VAR_DECL of type "int" with that name (returning the same global
-   for a name if we see the same name more than once).  */
-
-tree
-function_reader::parse_mem_expr (const char *desc)
-{
-  if (0 == strcmp (desc, "<retval>"))
-    {
-      tree fndecl = cfun->decl;
-      return DECL_RESULT (fndecl);
-    }
-
-  /* FIXME: use a hash rather than linear search.  */
-  int i;
-  tree t;
-  FOR_EACH_VEC_ELT (m_fake_scope, i, t)
-    if (0 == strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (t))))
-      return t;
-
-  /* Not found?  Create it.
-     This allows mimicing of real data but avoids having to specify
-     e.g. names of locals, params etc.
-     Though this way we don't know if we have a PARM_DECL vs a VAR_DECL,
-     and we don't know the types.  Fake it by making everything be
-     a VAR_DECL of "int" type.  */
-  t = build_decl (UNKNOWN_LOCATION, VAR_DECL,
-		  get_identifier (desc),
-		  integer_type_node);
-  m_fake_scope.safe_push (t);
-  return t;
-}
-
-/* Fix up the expr of an rtx (REG or MEM) based on a textual dump.  */
-
-void
-fixup_expr::apply (function_reader *reader) const
-{
-  tree expr = reader->parse_mem_expr (m_desc);
-  switch (GET_CODE (m_rtx))
-    {
-    case REG:
-      set_reg_attrs_for_decl_rtl (expr, m_rtx);
-      break;
-    case MEM:
-      set_mem_expr (m_rtx, expr);
-      break;
-    default:
-      gcc_unreachable ();
-    }
-}
-
-/* class function_reader : public rtx_reader */
-
-/* function_reader's constructor.  */
-
-function_reader::function_reader () : rtx_reader (),
-    m_first_insn (NULL)
-{
-  bitmap_initialize (&m_bb_indices, NULL);
-  bitmap_set_bit (&m_bb_indices, ENTRY_BLOCK);
-  bitmap_set_bit (&m_bb_indices, EXIT_BLOCK);
-}
-
-/* function_reader's destructor.  */
-
-function_reader::~function_reader ()
-{
-  int i;
-  fixup *f;
-  FOR_EACH_VEC_ELT (m_fixups, i, f)
-    delete f;
-}
-
-/* Implementation of rtx_reader::handle_unknown_directive.
-   Parse rtx instructions by calling read_rtx_code, calling
-   set_first_insn and set_last_insn as appropriate.  */
-
-void
-function_reader::handle_unknown_directive (file_location /*start_loc*/,
-					   const char *name)
-{
-  rtx x = read_rtx_code (name);
-  if (!x)
-    return;
-  rtx_insn *insn = as_a <rtx_insn *> (x);
-  set_last_insn (insn);
-  if (!m_first_insn)
-    {
-      m_first_insn = insn;
-      set_first_insn (insn);
-    }
-  m_insns_by_uid.put (INSN_UID (insn), insn);
-}
-
-/* Implementation of rtx_reader::add_fixup_insn_uid.
-   Record the information for later post-processing.  */
-
-void
-function_reader::add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
-				     int insn_uid)
-{
-  m_fixups.safe_push (new fixup_insn_uid (loc, insn, operand_idx, insn_uid));
-}
-
-/* Implementation of rtx_reader::add_fixup_bb.
-   Record the information for later post-processing.  */
-
-void
-function_reader::add_fixup_bb (file_location loc, rtx insn, int operand_idx,
-			       int bb_idx)
-{
-  bitmap_set_bit (&m_bb_indices, bb_idx);
-  m_fixups.safe_push (new fixup_bb (loc, insn, operand_idx, bb_idx));
-}
-
-/* Implementation of rtx_reader::add_fixup_note_insn_basic_block.
-   Record the information for later post-processing.  */
-
-void
-function_reader::add_fixup_note_insn_basic_block (file_location loc, rtx insn,
-						  int operand_idx, int bb_idx)
-{
-  m_fixups.safe_push (new fixup_note_insn_basic_block (loc, insn, operand_idx,
-						       bb_idx));
-}
-
-/* Implementation of rtx_reader::add_fixup_source_location.
-   Record the information for later post-processing.  */
-
-void
-function_reader::add_fixup_source_location (file_location loc, rtx insn,
-					    int operand_idx,
-					    const char *filename, int lineno)
-{
-  source_file *file = m_deferred_locations.get_source_file (filename);
-  source_line *line = file->get_source_line (lineno);
-  deferred_location *dloc = line->get_location (NULL, 0);
-  m_fixups.safe_push (new fixup_source_location (loc, insn, operand_idx, dloc));
-}
-
-/* Implementation of rtx_reader::add_fixup_jump_label.
-   Record the information for later post-processing.  */
-
-void
-function_reader::add_fixup_jump_label (file_location loc, rtx insn,
-				       int operand_idx,
-				       const char *label)
-{
-  m_fixups.safe_push (new fixup_jump_label (loc, insn, operand_idx, label));
-}
-
-/* Implementation of rtx_reader::add_fixup_expr.
-   Record the information for later post-processing.  */
-
-void
-function_reader::add_fixup_expr (file_location loc, rtx insn,
-				 const char *desc)
-{
-  gcc_assert (desc);
-  /* Fail early if the RTL reader erroneously hands us an int.  */
-  gcc_assert (!ISDIGIT (desc[0]));
-
-  m_fixups.safe_push (new fixup_expr (loc, insn, desc));
-}
-
-/* Set up state for the function *before* fixups are applied.
-
-   Create "cfun" and a decl for the function.
-   For the moment, every function decl is hardcoded as
-      int test_1 (int i, int j, int k);
-   Set up various other state:
-   - state set up by expand_function_start (e.g. crtl->return_rtx).
-   - the cfg and basic blocks (edges are created later, *after* fixups
-   are applied).
-   - add the function to the callgraph.  */
-
-void
-function_reader::create_function ()
-{
-  /* Currently we assume cfgrtl mode, rather than cfglayout mode.  */
-  if (0)
-    cfg_layout_rtl_register_cfg_hooks ();
-  else
-    rtl_register_cfg_hooks ();
-
-  /* Create cfun.  */
-  tree fn_name = get_identifier ("test_1");
-  tree int_type = integer_type_node;
-  tree return_type = int_type;
-  tree arg_types[3] = {int_type, int_type, int_type};
-  tree fn_type = build_function_type_array (return_type, 3, arg_types);
-  tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
-				 fn_type);
-  tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
-			     return_type);
-  DECL_ARTIFICIAL (resdecl) = 1;
-  DECL_IGNORED_P (resdecl) = 1;
-  DECL_RESULT (fndecl) = resdecl;
-  allocate_struct_function (fndecl, false);
-  /* This sets cfun.  */
-
-  /* Normally, various state gets set up by expand_function_start, e.g.
-     crtl->return_rtx, based on DECL_RESULT (fndecl).
-     We call it here to ensure the state is set up, with emit_insns as
-     false, so no new instructions are emitted.  */
-  current_function_decl = fndecl;
-  expand_function_start (fndecl, false);
-
-  create_cfg_and_basic_blocks ();
-  cfun->curr_properties = (PROP_cfg | PROP_rtl);
-
-  /* Do we need this to force cgraphunit.c to output the function? */
-  DECL_EXTERNAL (fndecl) = 0;
-  DECL_PRESERVE_P (fndecl) = 1;
-
-  /* Add to cgraph.  */
-  cgraph_node::add_new_function (fndecl, true /*lowered*/);
-
-  current_function_decl = NULL;
-}
-
-/* Apply all of the recorded fixups.  */
-
-void
-function_reader::apply_fixups ()
-{
-  m_deferred_locations.add_to_line_table ();
-  /* line_table should now be populated; every deferred_location should
-     now have an m_srcloc.  */
-
-  int i;
-  fixup *f;
-  FOR_EACH_VEC_ELT (m_fixups, i, f)
-    f->apply (this);
-}
-
-/* Given a UID value, try to locate a pointer to the corresponding
-   rtx_insn *, or NULL if if can't be found.  */
-
-rtx_insn **
-function_reader::get_insn_by_uid (int uid)
-{
-  return m_insns_by_uid.get (uid);
-}
-
-/* Create cfun's CFG and populate with blocks, a helper
-   function for function_reader::create_function ().
-
-   The edges are created later on, after fixups are applied.
-
-   We can't call create_basic_block and use the regular RTL block-creation
-   hooks, since this creates NOTE_INSN_BASIC_BLOCK instances.  We don't
-   want to do that; we want to use the notes we were provided with.
-
-   The term "index" has two meanings for basic blocks in a CFG:
-   (a) the "index" field within struct basic_block_def.
-   (b) the index of a basic_block within the cfg's x_basic_block_info
-   vector, as accessed via BASIC_BLOCK_FOR_FN.
-
-   These can get out-of-sync when basic blocks are optimized away.
-   They get back in sync by "compact_blocks".
-   We make the assumption that the CFG has been compacted, and
-   so we reconstruct cfun->cfg->x_basic_block_info->m_vecdata with NULL
-   values in it for any missing basic blocks, so that (a) == (b) for
-   all of the blocks we create.  The doubly-linked list of basic
-   blocks (next_bb/prev_bb) skips over these "holes".  */
-
-void
-function_reader::create_cfg_and_basic_blocks ()
-{
-  /* Create bare-bones cfg.  This creates the entry and exit blocks.  */
-  init_empty_tree_cfg_for_function (cfun);
-
-  /* Ensure that the vector of basic_block pointers is big enough.  */
-  unsigned highest_bb_idx = bitmap_last_set_bit (&m_bb_indices);
-  size_t new_size = highest_bb_idx + 1;
-  if (basic_block_info_for_fn (cfun)->length () < new_size)
-    vec_safe_grow_cleared (basic_block_info_for_fn (cfun), new_size);
-
-  /* Populate the vector.  */
-  unsigned bb_idx;
-  bitmap_iterator bi;
-  basic_block after = ENTRY_BLOCK_PTR_FOR_FN (cfun);
-  gcc_assert (after);
-  EXECUTE_IF_SET_IN_BITMAP (&m_bb_indices, 0, bb_idx, bi)
-    {
-      /* The entry and exit blocks were already created above.  */
-      if (bb_idx == ENTRY_BLOCK || bb_idx == EXIT_BLOCK)
-	{
-	  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_idx);
-	  init_rtl_bb_info (bb);
-	  continue;
-	}
-      basic_block bb = alloc_block ();
-      init_rtl_bb_info (bb);
-      bb->index = bb_idx;
-      bb->flags = BB_NEW | BB_RTL;
-      link_block (bb, after);
-
-      n_basic_blocks_for_fn (cfun)++;
-      SET_BASIC_BLOCK_FOR_FN (cfun, bb_idx, bb);
-      BB_SET_PARTITION (bb, BB_UNPARTITIONED);
-
-      /* Tag the block so that we know it has been used when considering
-	 other basic block notes.  */
-      bb->aux = bb;
-
-      after = bb;
-    }
-
-  last_basic_block_for_fn (cfun) = highest_bb_idx + 1;
-}
-
-/* Visit every LABEL_REF within JUMP_INSN, calling CB on it, providing it
-   with USER_DATA.
-   FIXME: is there a preexisting way to do this?  */
-
-static void
-for_each_label_ref (rtx_jump_insn *jump_insn,
-		    void (*cb) (rtx_jump_insn *jump_insn,
-				rtx label_ref,
-				void *user_data),
-		    void *user_data)
-{
-  if (any_condjump_p (jump_insn))
-    {
-      rtx label_ref = condjump_label (jump_insn);
-      cb (jump_insn, label_ref, user_data);
-      return;
-    }
-
-  if (simplejump_p (jump_insn))
-    {
-      rtx label_ref = SET_SRC (PATTERN (jump_insn));
-      cb (jump_insn, label_ref, user_data);
-      return;
-    }
-
-  rtx_jump_table_data *tablep;
-  if (tablejump_p (jump_insn, NULL, &tablep))
-    {
-      gcc_assert (tablep);
-      rtvec labels = tablep->get_labels ();
-      int i, veclen = GET_NUM_ELEM (labels);
-      for (i = 0; i < veclen; ++i)
-	{
-	  rtx label_ref = RTVEC_ELT (labels, i);
-	  cb (jump_insn, label_ref, user_data);
-	}
-      return;
-    }
-
-  if (ANY_RETURN_P (PATTERN (jump_insn)))
-    return;
-
-  /* TODO: something else?  */
-  gcc_unreachable ();
-}
-
-/* Create an edge from SRC to DST, with the given flags.  */
-
-static void
-add_edge (basic_block src, basic_block dst, int flags)
-{
-  if (0)
-    fprintf (stderr, "making edge %i->%i\n",
-	     src->index, dst->index);
-  unchecked_make_edge (src, dst, flags);
-}
-
-/* Edge-creation callback for function_reader::create_cfg_edges.  */
-
-static void
-add_edge_cb (rtx_jump_insn *jump_insn, rtx label_ref, void */*user_data*/)
-{
-  gcc_assert (jump_insn);
-  gcc_assert (label_ref);
-  rtx_insn *label_insn = as_a <rtx_insn *> (LABEL_REF_LABEL (label_ref));
-  add_edge (BLOCK_FOR_INSN (jump_insn), BLOCK_FOR_INSN (label_insn), 0);
-}
-
-/* Create edges within cfun's CFG, by examining instructions in the
-   basic blocks and reconstructing the edges accordingly.
-   This is done after fixups are applied, since the latter is responsible
-   for setting up BB_HEAD and BB_END within each basic block.
-
-   This assumes cfgrtl mode, in which the edges are implicit from
-   the jump instructions.  It won't work for cfglayout mode, which
-   represents unconditional jumps purely as edges within the CFG,
-   without instructions, and this information isn't (currently)
-   written out to dumps.  */
-
-void
-function_reader::create_cfg_edges ()
-{
-  /* Create edge from ENTRY_BLOCK to block of first insn.  */
-  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
-  add_edge (entry, entry->next_bb, EDGE_FALLTHRU);
-
-  /* Create other edges.
-
-     The edge from the block of last insn to EXIT_BLOCK is created
-     below, by fall-through from the end of its block.  */
-  basic_block bb;
-  FOR_ALL_BB_FN (bb, cfun)
-    {
-      if (!BB_HEAD (bb))
-	continue;
-      rtx_insn *end_insn = BB_END (bb);
-      if (rtx_jump_insn *jump_insn = dyn_cast <rtx_jump_insn *> (end_insn))
-	{
-	  if (0)
-	    fprintf (stderr, "bb %i ends in jump\n", bb->index);
-	  if (!any_uncondjump_p (end_insn))
-	    {
-	      /* Add fallthrough edge first.  */
-	      gcc_assert (bb->next_bb);
-	      add_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-	    }
-	  for_each_label_ref (jump_insn, add_edge_cb, NULL);
-	}
-      else
-	{
-	  if (0)
-	    fprintf (stderr, "bb %i ends in non-jump\n", bb->index);
-	  if (bb->next_bb != NULL)
-	    {
-	      /* Add fallthrough edge.  */
-	      gcc_assert (bb->next_bb);
-	      add_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-	    }
-	}
-    }
-}
-
 /*  Locate and run PASS_NAME on cfun.  */
 
 static void
@@ -968,26 +240,9 @@ rtl_langhook_parse_file (void)
   argv.safe_push (progname);
   for (unsigned i = 0; i < num_in_fnames; i++)
     argv.safe_push (in_fnames[i]);
-  function_reader reader;
-  if (!reader.read_md_files (argv.length (), argv.address (), NULL))
+  if (!read_rtl_function_body (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.  */
@@ -996,7 +251,7 @@ rtl_langhook_parse_file (void)
       FILE *out = fopen (roundtrip_filename, "w");
       if (out)
 	{
-	  print_rtl_with_bb (out, reader.get_first_insn (), 1024);
+	  print_rtl_with_bb (out, get_insns (), 1024);
 	  fclose (out);
 	}
       else
-- 
1.8.5.3

