diff mbox

[v2] Introduce class rtx_reader

Message ID 1474477046-19647-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

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

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

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

Thanks.

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

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

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

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

Comments

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

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

Richard
diff mbox

Patch

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