From 1c7352cde8a759e414b61d3aeaf40eda67f8dd75 Mon Sep 17 00:00:00 2001
From: Zack Weinberg <zackw@panix.com>
Date: Mon, 23 Jan 2006 15:15:05 +0000
Subject: [PATCH] r110123@banpei: zack | 2006-01-22 14:44:34 -0800

 r110123@banpei:  zack | 2006-01-22 14:44:34 -0800
 	* genconditions.c (condition_table, add_condition): Delete.
 	(write_conditions): Don't emit n_insn_conditions nor
 	insn_elision_unavailable.  Issue the gcc version #ifdef here,
 	inside the table, with no #else clause ...
 	(write_header): ...not here.
 	(write_writer): New function.
 	(main): Don't initialize condition_table.  Use add_c_test.
 	Call write_writer.
 	* gensupport.c (init_md_reader_args_cb): Handle multiple input
 	files on the command line.
 	(maybe_eval_c_test): Don't check insn_elision_unavailable.
 	Return -1 if there is no entry in the table, don't abort.
 	(add_c_test, traverse_c_tests): New functions.
 	* gensupport.h (insn_elision_unavailable, insn_conditions)
 	(n_insn_conditions): Delete declarations.
 	(add_c_test, traverse_c_tests): Declare.
 	* read-rtl.c: Include gensupport.h.
 	(read_conditions): New function.
 	(read_rtx): If read_rtx_1 returns 0, treat as EOF.
 	(read_rtx_1): If we get EOF when we were looking for an initial
 	open paren, return 0.  Call read_conditions when appropriate.
 	* Makefile.in: Kill BUILD_EARLY_SUPPORT and all references to
 	dummy-conditions.o.  Eliminate references to insn-conditions.o,
 	or change them to build/gencondmd.o, as appropriate.  Remove
 	insn-constants.h from $(simple_generated_h) and insn-conditions.c
 	from $(simple_generated_c).  For all files remaining in those
 	two lists, add insn-conditions.md to the generator command line.
 	Give insn-constants.h/s-constants their own rules.  Add rules
 	for build/gencondmd.c, s-conditions, insn-conditions.md, s-condmd.
 	(build/read-rtl.o): Depend on gensupport.h.
 	(genprognormal): Include preds.
 	(genprogearly): Rename genprognoprint; only difference is now that
 	they don't link with $(BUILD_PRINT).
 	* dummy-conditions.c: Delete.

From-SVN: r110119
---
 gcc/ChangeLog          |  37 +++++++
 gcc/Makefile.in        |  74 +++++++++-----
 gcc/dummy-conditions.c |  42 --------
 gcc/genconditions.c    |  68 ++++++-------
 gcc/gensupport.c       | 220 ++++++++++++++++++++++++++++-------------
 gcc/gensupport.h       |  16 ++-
 gcc/read-rtl.c         |  74 +++++++++++++-
 7 files changed, 343 insertions(+), 188 deletions(-)
 delete mode 100644 gcc/dummy-conditions.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8f01cd23c135..6b723cc965bd 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,40 @@
+2006-01-22  Zack Weinberg  <zackw@panix.com>
+
+	* genconditions.c (condition_table, add_condition): Delete.
+	(write_conditions): Don't emit n_insn_conditions nor
+	insn_elision_unavailable.  Issue the gcc version #ifdef here,
+	inside the table, with no #else clause ...
+	(write_header): ...not here.
+	(write_writer): New function.
+	(main): Don't initialize condition_table.  Use add_c_test.
+	Call write_writer.
+	* gensupport.c (init_md_reader_args_cb): Handle multiple input
+	files on the command line.
+	(maybe_eval_c_test): Don't check insn_elision_unavailable.
+	Return -1 if there is no entry in the table, don't abort.
+	(add_c_test, traverse_c_tests): New functions.
+	* gensupport.h (insn_elision_unavailable, insn_conditions)
+	(n_insn_conditions): Delete declarations.
+	(add_c_test, traverse_c_tests): Declare.
+	* read-rtl.c: Include gensupport.h.
+	(read_conditions): New function.
+	(read_rtx): If read_rtx_1 returns 0, treat as EOF.
+	(read_rtx_1): If we get EOF when we were looking for an initial
+	open paren, return 0.  Call read_conditions when appropriate.
+	* Makefile.in: Kill BUILD_EARLY_SUPPORT and all references to
+	dummy-conditions.o.  Eliminate references to insn-conditions.o,
+	or change them to build/gencondmd.o, as appropriate.  Remove
+	insn-constants.h from $(simple_generated_h) and insn-conditions.c
+	from $(simple_generated_c).  For all files remaining in those
+	two lists, add insn-conditions.md to the generator command line.
+	Give insn-constants.h/s-constants their own rules.  Add rules
+	for build/gencondmd.c, s-conditions, insn-conditions.md, s-condmd.
+	(build/read-rtl.o): Depend on gensupport.h.
+	(genprognormal): Include preds.
+	(genprogearly): Rename genprognoprint; only difference is now that
+	they don't link with $(BUILD_PRINT).
+	* dummy-conditions.c: Delete.
+
 2006-01-22  Zack Weinberg  <zackw@panix.com>
 
 	* genextract.c: Don't include insn-config.h.  Do include vec.h.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 68bbb698f3cf..c6eec9832c16 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -198,7 +198,7 @@ GCC_WARN_CFLAGS = $(LOOSE_WARN) $($(@D)-warn) $(NOCOMMON_FLAG) $($@-warn)
 # These files are to have -Werror bypassed in stage2:
 # These are very hard to completely clean due to target complexities.
 gcc.o-warn = -Wno-error
-build/insn-conditions.o-warn = -Wno-error
+build/gencondmd.o-warn = -Wno-error
 # Bison-1.75 output often yields (harmless) -Wtraditional warnings
 build/gengtype-yacc.o-warn = -Wno-error
 # flex output may yield harmless "no previous prototype" warnings
@@ -840,9 +840,7 @@ BUILD_LIBS = $(BUILD_LIBIBERTY)
 
 BUILD_RTL = build/rtl.o build/read-rtl.o build/ggc-none.o \
 	    build/min-insn-modes.o
-BUILD_SUPPORT = build/gensupport.o build/insn-conditions.o
-BUILD_EARLY_SUPPORT = build/gensupport.o build/dummy-conditions.o
-
+BUILD_SUPPORT = build/gensupport.o
 BUILD_PRINT = build/print-rtl.o
 BUILD_ERRORS = build/errors.o
 BUILD_VARRAY = build/varray.o
@@ -1019,7 +1017,7 @@ STAGECOPYSTUFF = insn-flags.h insn-config.h insn-codes.h \
  insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \
  insn-attr.h insn-attrtab.c insn-opinit.c insn-preds.c insn-constants.h \
  tm-preds.h \
- tree-check.h insn-conditions.c min-insn-modes.c insn-modes.c insn-modes.h \
+ tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \
  genrtl.c genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-gen.h
 
 # Files to be moved away after each stage in building.
@@ -2678,26 +2676,38 @@ insn-recog.o : insn-recog.c $(CONFIG_H) $(SYSTEM_H) coretypes.h		\
 # The "; @true" construct forces Make to recheck the timestamp on the
 # target file.
 
-simple_generated_h = insn-attr.h insn-codes.h insn-config.h	\
-		     insn-constants.h insn-flags.h 
+simple_generated_h = insn-attr.h insn-codes.h insn-config.h insn-flags.h 
 
-simple_generated_c = insn-attrtab.c insn-conditions.c insn-emit.c \
-		     insn-extract.c insn-opinit.c insn-output.c \
-		     insn-peep.c insn-recog.c
+simple_generated_c = insn-attrtab.c insn-emit.c insn-extract.c	\
+		     insn-opinit.c insn-output.c insn-peep.c	\
+		     insn-recog.c
 
 $(simple_generated_h): insn-%.h: s-%; @true
 
-$(simple_generated_h:insn-%.h=s-%): s-%: $(MD_DEPS) build/gen%$(build_exeext)
-	$(RUN_GEN) build/gen$*$(build_exeext) $(md_file) > tmp-$*.h
+$(simple_generated_h:insn-%.h=s-%): s-%: build/gen%$(build_exeext) \
+  $(MD_DEPS) insn-conditions.md
+	$(RUN_GEN) build/gen$*$(build_exeext) $(md_file) \
+	  insn-conditions.md > tmp-$*.h
 	$(SHELL) $(srcdir)/../move-if-change tmp-$*.h insn-$*.h
 	$(STAMP) s-$*
 
 $(simple_generated_c): insn-%.c: s-%; @true
-$(simple_generated_c:insn-%.c=s-%): s-%: $(MD_DEPS) build/gen%$(build_exeext)
-	$(RUN_GEN) build/gen$*$(build_exeext) $(md_file) > tmp-$*.c
+$(simple_generated_c:insn-%.c=s-%): s-%: build/gen%$(build_exeext) \
+  $(MD_DEPS) insn-conditions.md
+	$(RUN_GEN) build/gen$*$(build_exeext) $(md_file) \
+	  insn-conditions.md > tmp-$*.c
 	$(SHELL) $(srcdir)/../move-if-change tmp-$*.c insn-$*.c
 	$(STAMP) s-$*
 
+# genconstants needs to run before insn-conditions.md is available
+# (because the constants may be used in the conditions).
+insn-constants.h: s-constants; @true
+s-constants: build/genconstants$(build_exeext) $(MD_DEPS)
+	$(RUN_GEN) build/genconstants$(build_exeext) $(md_file) \
+	  > tmp-constants.h
+	$(SHELL) $(srcdir)/../move-if-change tmp-constants.h insn-constants.h
+	$(STAMP) s-constants
+
 # gencheck doesn't read the machine description, and the file produced
 # doesn't use the insn-* convention.
 tree-check.h: s-check ; @true
@@ -2706,6 +2716,20 @@ s-check : build/gencheck$(build_exeext)
 	$(SHELL) $(srcdir)/../move-if-change tmp-check.h tree-check.h
 	$(STAMP) s-check
 
+# gencondmd doesn't use the standard naming convention.
+build/gencondmd.c: s-conditions; @true
+s-conditions: $(MD_DEPS) build/genconditions$(build_exeext)
+	$(RUN_GEN) build/genconditions$(build_exeext) $(md_file) > tmp-condmd.c
+	$(SHELL) $(srcdir)/../move-if-change tmp-condmd.c build/gencondmd.c
+	$(STAMP) s-conditions
+
+insn-conditions.md: s-condmd; @true
+s-condmd: build/gencondmd$(build_exeext)
+	$(RUN_GEN) build/gencondmd$(build_exeext) > tmp-cond.md
+	$(SHELL) $(srcdir)/../move-if-change tmp-cond.md insn-conditions.md
+	$(STAMP) s-condmd
+
+
 # These files are generated by running the same generator more than
 # once with different options, so they have custom rules.  The
 # stampfile idiom is the same.
@@ -2859,7 +2883,6 @@ build/%.o :  # dependencies provided by explicit rule later
 
 # Header dependencies for the programs that generate source code.
 # These are library modules...
-build/dummy-conditions.o : dummy-conditions.c
 build/errors.o : errors.c $(BCONFIG_H) $(SYSTEM_H) errors.h
 build/gensupport.o: gensupport.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h	\
   $(GTM_H) $(RTL_BASE_H) $(OBSTACK_H) errors.h $(HASHTAB_H)		\
@@ -2871,16 +2894,16 @@ build/min-insn-modes.o : min-insn-modes.c $(BCONFIG_H) $(SYSTEM_H)	\
 build/print-rtl.o: print-rtl.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h	\
   $(GTM_H) $(RTL_BASE_H)
 build/read-rtl.o: read-rtl.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h	\
-  $(GTM_H) $(RTL_BASE_H) $(OBSTACK_H) $(HASHTAB_H)
+  $(GTM_H) $(RTL_BASE_H) $(OBSTACK_H) $(HASHTAB_H) gensupport.h
 build/rtl.o: rtl.c $(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H)	\
   $(RTL_H) real.h $(GGC_H) errors.h
 build/varray.o: varray.c $(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H)	\
   $(VARRAY_H) $(RTL_BASE_H) $(GGC_H) $(TREE_H) bitmap.h errors.h
 build/vec.o : vec.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) coretypes.h vec.h \
    $(GGC_H) toplev.h
-build/insn-conditions.o : insn-conditions.c $(CONFIG_H) $(SYSTEM_H)	\
-  $(GTM_H) $(RTL_H) $(TM_P_H) $(REGS_H) $(FUNCTION_H) $(RECOG_H) real.h	\
-  output.h $(FLAGS_H) hard-reg-set.h $(RESOURCE_H) toplev.h reload.h	\
+build/gencondmd.o : build/gencondmd.c $(CONFIG_H) $(SYSTEM_H) $(GTM_H)	\
+  $(RTL_H) $(TM_P_H) $(REGS_H) $(FUNCTION_H) $(RECOG_H) real.h output.h	\
+  $(FLAGS_H) hard-reg-set.h $(RESOURCE_H) toplev.h reload.h		\
   gensupport.h insn-constants.h coretypes.h
 
 # ...these are the programs themselves.
@@ -2942,15 +2965,16 @@ build/gen%$(build_exeext): build/gen%.o $(BUILD_LIBDEPS)
 	    $(filter-out $(BUILD_LIBDEPS), $^) $(BUILD_LIBS)
 
 # All these programs have the same additional dependency set.
-genprognormal = attr codes config emit extract flags opinit output peep recog
+genprognormal = attr codes config emit extract flags opinit output peep recog \
+		preds
 $(genprognormal:%=build/gen%$(build_exeext)): $(BUILD_RTL) $(BUILD_SUPPORT) \
   $(BUILD_PRINT) $(BUILD_ERRORS)
 
-# And all of these, but it's a different set.
-genprogearly = mddeps constants conditions preds
-$(genprogearly:%=build/gen%$(build_exeext)): $(BUILD_RTL) $(BUILD_ERRORS) \
-  $(BUILD_EARLY_SUPPORT)
-build/genpreds$(build_exeext) : $(BUILD_PRINT)
+# These don't have the glue to link with print-rtl.o.
+genprognoprint = mddeps constants conditions
+$(genprognoprint:%=build/gen%$(build_exeext)): $(BUILD_RTL) $(BUILD_SUPPORT) \
+  $(BUILD_ERRORS)
+
 
 build/gengenrtl$(build_exeext) : $(BUILD_ERRORS)
 build/genmodes$(build_exeext) : $(BUILD_ERRORS)
diff --git a/gcc/dummy-conditions.c b/gcc/dummy-conditions.c
deleted file mode 100644
index 14a28b628e75..000000000000
--- a/gcc/dummy-conditions.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Support for calculating constant conditions.
-   Copyright (C) 2002, 2004 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 2, 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 COPYING.  If not, write to
-   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-#include <stddef.h>  /* for size_t */
-
-/* MD generators that are run before insn-conditions.c exists should
-   link against this file instead.  Currently that is genconditions
-   and genconstants.  */
-
-/* In order to avoid dragging in all the headers that are needed to
-   declare things that gensupport.h uses, we duplicate the declaration
-   of struct c_test here.  (In particular we do not want to have to
-   include tm.h nor rtl.h in this file.)  */
-struct c_test
-{
-  const char *expr;
-  int value;
-};
-
-/* Empty conditions table to prevent link errors.  */
-const struct c_test insn_conditions[1] = { { 0, 0 } };
-const size_t n_insn_conditions = 0;
-
-/* Disable insn elision, since it is currently impossible.  */
-const int insn_elision_unavailable = 1;
diff --git a/gcc/genconditions.c b/gcc/genconditions.c
index bdb3d30e27ad..10dfc5896b48 100644
--- a/gcc/genconditions.c
+++ b/gcc/genconditions.c
@@ -38,31 +38,10 @@
 /* so we can include except.h in the generated file.  */
 static int saw_eh_return;
 
-static htab_t condition_table;
-
-static void add_condition	(const char *);
 static void write_header	(void);
 static void write_conditions	(void);
 static int write_one_condition	(void **, void *);
 
-/* Record the C test expression EXPR in the condition_table.
-   Duplicates clobber previous entries, which leaks memory, but
-   we don't care for this application.  */
-
-static void
-add_condition (const char *expr)
-{
-  struct c_test *test;
-
-  if (expr[0] == 0)
-    return;
-
-  test = XNEW (struct c_test);
-  test->expr = expr;
-
-  *(htab_find_slot (condition_table, test, INSERT)) = test;
-}
-
 /* Generate the header for insn-conditions.c.  */
 
 static void
@@ -86,13 +65,6 @@ write_header (void)
 
   puts ("\
 #include \"system.h\"\n\
-/* If we don't have __builtin_constant_p, or it's not acceptable in array\n\
-   initializers, fall back to assuming that all conditions potentially\n\
-   vary at run time.  It works in 3.0.1 and later; 3.0 only when not\n\
-   optimizing.  */\n\
-#if GCC_VERSION < 3001\n\
-#include \"dummy-conditions.c\"\n\
-#else\n\
 #include \"coretypes.h\"\n\
 #include \"tm.h\"\n\
 #include \"rtl.h\"\n\
@@ -172,15 +144,35 @@ write_conditions (void)
    Each condition is mapped to its truth value (0 or 1), or -1 if that\n\
    cannot be calculated at compile time. */\n\
 \n\
-const struct c_test insn_conditions[] = {");
+static const struct c_test insn_conditions[] = {\n			\
+/* If we don't have __builtin_constant_p, or it's not acceptable in array\n\
+   initializers, fall back to assuming that all conditions potentially\n\
+   vary at run time.  It works in 3.0.1 and later; 3.0 only when not\n\
+   optimizing.  */\n\
+#if GCC_VERSION >= 3001");
 
-  htab_traverse (condition_table, write_one_condition, 0);
+  traverse_c_tests (write_one_condition, 0);
 
-  puts ("};\n");
+  puts ("#endif\n};\n");
+}
 
-  printf ("const size_t n_insn_conditions = %lu;\n",
-	  (unsigned long) htab_elements (condition_table));
-  puts ("const int insn_elision_unavailable = 0;\n#endif");
+/* Emit code which will convert the C-format table to a
+   (define_conditions) form, which the MD reader can understand.
+   The result will be added to the set of files scanned by
+   'downstream' generators.  */
+static void
+write_writer (void)
+{
+  puts ("int\nmain(void)\n{\n\
+  unsigned int i;\n\
+\n\
+  puts (\"(define_conditions [\");\n\
+  for (i = 0; i < ARRAY_SIZE (insn_conditions); i++)\n\
+    printf (\"  (%d \\\"%s\\\")\\n\",\n\
+	    insn_conditions[i].value, insn_conditions[i].expr);\n\
+  puts (\"])\");\n\
+  fflush (stdout);\n\
+  return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);\n}");
 }
 
 int
@@ -195,10 +187,7 @@ main (int argc, char **argv)
   if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
     return (FATAL_EXIT_CODE);
 
-  condition_table = htab_create (1000, hash_c_test, cmp_c_test, NULL);
-
   /* Read the machine description.  */
-
   while (1)
     {
       desc = read_md_rtx (&pattern_lineno, &code);
@@ -214,7 +203,7 @@ main (int argc, char **argv)
 
 	case DEFINE_INSN:
 	case DEFINE_EXPAND:
-	  add_condition (XSTR (desc, 2));
+	  add_c_test (XSTR (desc, 2), -1);
 	  /* except.h needs to know whether there is an eh_return
 	     pattern in the machine description.  */
 	  if (!strcmp (XSTR (desc, 0), "eh_return"))
@@ -224,13 +213,14 @@ main (int argc, char **argv)
 	case DEFINE_SPLIT:
 	case DEFINE_PEEPHOLE:
 	case DEFINE_PEEPHOLE2:
-	  add_condition (XSTR (desc, 1));
+	  add_c_test (XSTR (desc, 1), -1);
 	  break;
 	}
     }
 
   write_header ();
   write_conditions ();
+  write_writer ();
 
   fflush (stdout);
   return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index 644b3b920a3d..94d27aca9753 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -901,93 +901,148 @@ int
 init_md_reader_args_cb (int argc, char **argv, bool (*parse_opt)(const char *))
 {
   FILE *input_file;
-  int i, lineno;
-  size_t ix;
+  int c, i, lineno;
   char *lastsl;
   rtx desc;
+  bool no_more_options;
+  bool already_read_stdin;
 
   /* Unlock the stdio streams.  */
   unlock_std_streams ();
 
+  /* First we loop over all the options.  */
   for (i = 1; i < argc; i++)
     {
       if (argv[i][0] != '-')
+	continue;
+      
+      c = argv[i][1];
+      switch (c)
 	{
-	  if (in_fname)
-	    fatal ("too many input files");
+	case 'I':		/* Add directory to path for includes.  */
+	  {
+	    struct file_name_list *dirtmp;
+
+	    dirtmp = XNEW (struct file_name_list);
+	    dirtmp->next = 0;	/* New one goes on the end */
+	    if (first_dir_md_include == 0)
+	      first_dir_md_include = dirtmp;
+	    else
+	      last_dir_md_include->next = dirtmp;
+	    last_dir_md_include = dirtmp;	/* Tail follows the last one */
+	    if (argv[i][1] == 'I' && argv[i][2] != 0)
+	      dirtmp->fname = argv[i] + 2;
+	    else if (i + 1 == argc)
+	      fatal ("directory name missing after -I option");
+	    else
+	      dirtmp->fname = argv[++i];
+	    if (strlen (dirtmp->fname) > max_include_len)
+	      max_include_len = strlen (dirtmp->fname);
+	  }
+	  break;
 
-	  in_fname = argv[i];
-	}
-      else
-	{
-	  int c = argv[i][1];
-	  switch (c)
-	    {
-	    case 'I':		/* Add directory to path for includes.  */
-	      {
-		struct file_name_list *dirtmp;
-
-		dirtmp = XNEW (struct file_name_list);
-		dirtmp->next = 0;	/* New one goes on the end */
-		if (first_dir_md_include == 0)
-		  first_dir_md_include = dirtmp;
-		else
-		  last_dir_md_include->next = dirtmp;
-		last_dir_md_include = dirtmp;	/* Tail follows the last one */
-		if (argv[i][1] == 'I' && argv[i][2] != 0)
-		  dirtmp->fname = argv[i] + 2;
-		else if (i + 1 == argc)
-		  fatal ("directory name missing after -I option");
-		else
-		  dirtmp->fname = argv[++i];
-		if (strlen (dirtmp->fname) > max_include_len)
-		  max_include_len = strlen (dirtmp->fname);
-	      }
-	      break;
-	    default:
-	      /* The program may have provided a callback so it can
-		 accept its own options.  */
-	      if (parse_opt && parse_opt (argv[i]))
-		break;
-
-	      fatal ("invalid option `%s'", argv[i]);
-	    }
-	}
-    }
+	case '\0':
+	  /* An argument consisting of exactly one dash is a request to
+	     read stdin.  This will be handled in the second loop.  */
+	  continue;
 
-  if (!in_fname)
-    fatal ("no input file name");
+	case '-':
+	  /* An argument consisting of just two dashes causes option
+	     parsing to cease.  */
+	  if (argv[i][2] == '\0')
+	    goto stop_parsing_options;
 
-  lastsl = strrchr (in_fname, '/');
-  if (lastsl != NULL)
-    base_dir = save_string (in_fname, lastsl - in_fname + 1 );
+	default:
+	  /* The program may have provided a callback so it can
+	     accept its own options.  */
+	  if (parse_opt && parse_opt (argv[i]))
+	    break;
 
-  read_rtx_filename = in_fname;
-  input_file = fopen (in_fname, "r");
-  if (input_file == 0)
-    {
-      perror (in_fname);
-      return FATAL_EXIT_CODE;
+	  fatal ("invalid option `%s'", argv[i]);
+	}
     }
 
-  /* Initialize the table of insn conditions.  */
-  condition_table = htab_create (n_insn_conditions,
-				 hash_c_test, cmp_c_test, NULL);
-
-  for (ix = 0; ix < n_insn_conditions; ix++)
-    *(htab_find_slot (condition_table, &insn_conditions[ix], INSERT))
-      = (void *) &insn_conditions[ix];
+ stop_parsing_options:
 
+  /* Prepare to read input.  */
+  condition_table = htab_create (500, hash_c_test, cmp_c_test, NULL);
   init_predicate_table ();
-
   obstack_init (rtl_obstack);
   errors = 0;
   sequence_num = 0;
+  no_more_options = false;
+  already_read_stdin = false;
 
-  /* Read the entire file.  */
-  while (read_rtx (input_file, &desc, &lineno))
-    process_rtx (desc, lineno);
-  fclose (input_file);
+
+  /* Now loop over all input files.  */
+  for (i = 1; i < argc; i++)
+    {
+      if (argv[i][0] == '-')
+	{
+	  if (argv[i][1] == '\0')
+	    {
+	      /* Read stdin.  */
+	      if (already_read_stdin)
+		fatal ("cannot read standard input twice");
+	      
+	      base_dir = NULL;
+	      read_rtx_filename = in_fname = "<stdin>";
+	      read_rtx_lineno = 1;
+	      input_file = stdin;
+	      already_read_stdin = true;
+
+	      while (read_rtx (input_file, &desc, &lineno))
+		process_rtx (desc, lineno);
+	      fclose (input_file);
+	      continue;
+	    }
+	  else if (argv[i][1] == '-' && argv[i][2] == '\0')
+	    {
+	      /* No further arguments are to be treated as options.  */
+	      no_more_options = true;
+	      continue;
+	    }
+	  else if (!no_more_options)
+	    continue;
+	}
+
+      /* If we get here we are looking at a non-option argument, i.e.
+	 a file to be processed.  */
+
+      in_fname = argv[i];
+      lastsl = strrchr (in_fname, '/');
+      if (lastsl != NULL)
+	base_dir = save_string (in_fname, lastsl - in_fname + 1 );
+      else
+	base_dir = NULL;
+
+      read_rtx_filename = in_fname;
+      read_rtx_lineno = 1;
+      input_file = fopen (in_fname, "r");
+      if (input_file == 0)
+	{
+	  perror (in_fname);
+	  return FATAL_EXIT_CODE;
+	}
+
+      while (read_rtx (input_file, &desc, &lineno))
+	process_rtx (desc, lineno);
+      fclose (input_file);
+    }
+
+  /* If we get to this point without having seen any files to process,
+     read standard input now.  */
+  if (!in_fname)
+    {
+      base_dir = NULL;
+      read_rtx_filename = in_fname = "<stdin>";
+      read_rtx_lineno = 1;
+      input_file = stdin;
+
+      while (read_rtx (input_file, &desc, &lineno))
+	process_rtx (desc, lineno);
+      fclose (input_file);
+    }
 
   /* Process define_cond_exec patterns.  */
   if (define_cond_exec_queue != NULL)
@@ -1119,16 +1174,41 @@ maybe_eval_c_test (const char *expr)
   if (expr[0] == 0)
     return 1;
 
-  if (insn_elision_unavailable)
-    return -1;
-
   dummy.expr = expr;
   test = (const struct c_test *)htab_find (condition_table, &dummy);
-  gcc_assert (test);
-
+  if (!test)
+    return -1;
   return test->value;
 }
 
+/* Record the C test expression EXPR in the condition_table, with
+   value VAL.  Duplicates clobber previous entries.  */
+
+void
+add_c_test (const char *expr, int value)
+{
+  struct c_test *test;
+
+  if (expr[0] == 0)
+    return;
+
+  test = XNEW (struct c_test);
+  test->expr = expr;
+  test->value = value;
+
+  *(htab_find_slot (condition_table, test, INSERT)) = test;
+}
+
+/* For every C test, call CALLBACK with two arguments: a pointer to
+   the condition structure and INFO.  Stops when CALLBACK returns zero.  */
+void
+traverse_c_tests (htab_trav callback, void *info)
+{
+  if (condition_table)
+    htab_traverse (condition_table, callback, info);
+}
+
+
 /* Given a string, return the number of comma-separated elements in it.
    Return 0 for the null string.  */
 int
diff --git a/gcc/gensupport.h b/gcc/gensupport.h
index 51f37b7bc7ca..53cbdc23b6ea 100644
--- a/gcc/gensupport.h
+++ b/gcc/gensupport.h
@@ -37,31 +37,27 @@ extern void message_with_line (int, const char *, ...)
    Must be set before calling init_md_reader.  */
 extern int insn_elision;
 
-/* If this is 1, the insn elision table doesn't even exist yet;
-   maybe_eval_c_test will always return -1.  This is distinct from
-   insn_elision because genflags and gencodes need to see all the
-   patterns, but treat elided patterns differently.  */
-extern const int insn_elision_unavailable;
-
 /* If the C test passed as the argument can be evaluated at compile
    time, return its truth value; else return -1.  The test must have
    appeared somewhere in the machine description when genconditions
    was run.  */
 extern int maybe_eval_c_test (const char *);
 
-/* This table should not be accessed directly; use maybe_eval_c_test.  */
+/* Add an entry to the table of conditions.  Used by genconditions and
+   by read-rtl.c.  */
+extern void add_c_test (const char *, int);
+
+/* This structure is used internally by gensupport.c and genconditions.c.  */
 struct c_test
 {
   const char *expr;
   int value;
 };
 
-extern const struct c_test insn_conditions[];
-extern const size_t n_insn_conditions;
-
 #ifdef __HASHTAB_H__
 extern hashval_t hash_c_test (const void *);
 extern int cmp_c_test (const void *, const void *);
+extern void traverse_c_tests (htab_trav, void *);
 #endif
 
 extern int n_comma_elts	(const char *);
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 79f40508d3be..b4b105108eb5 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -31,6 +31,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "rtl.h"
 #include "obstack.h"
 #include "hashtab.h"
+#include "gensupport.h"
 
 static htab_t md_constants;
 
@@ -138,6 +139,7 @@ static void read_escape (FILE *);
 static hashval_t def_hash (const void *);
 static int def_name_eq_p (const void *, const void *);
 static void read_constants (FILE *infile, char *tmp_char);
+static void read_conditions (FILE *infile, char *tmp_char);
 static void validate_const_int (FILE *, const char *);
 static int find_macro (struct macro_group *, const char *, FILE *);
 static struct mapping *read_mapping (struct macro_group *, htab_t, FILE *);
@@ -1205,6 +1207,58 @@ traverse_md_constants (htab_trav callback, void *info)
   if (md_constants)
     htab_traverse (md_constants, callback, info);
 }
+
+/* INFILE is a FILE pointer to read text from.  TMP_CHAR is a buffer
+   suitable to read a name or number into.  Process a
+   define_conditions directive, starting with the optional space after
+   the "define_conditions".  The directive looks like this:
+
+     (define_conditions [
+        (number "string")
+        (number "string")
+        ...
+     ])
+
+   It's not intended to appear in machine descriptions.  It is
+   generated by (the program generated by) genconditions.c, and
+   slipped in at the beginning of the sequence of MD files read by
+   most of the other generators.  */
+static void
+read_conditions (FILE *infile, char *tmp_char)
+{
+  int c;
+
+  c = read_skip_spaces (infile);
+  if (c != '[')
+    fatal_expected_char (infile, '[', c);
+
+  while ( (c = read_skip_spaces (infile)) != ']')
+    {
+      char *expr;
+      int value;
+
+      if (c != '(')
+	fatal_expected_char (infile, '(', c);
+
+      read_name (tmp_char, infile);
+      validate_const_int (infile, tmp_char);
+      value = atoi (tmp_char);
+
+      c = read_skip_spaces (infile);
+      if (c != '"')
+	fatal_expected_char (infile, '"', c);
+      expr = read_quoted_string (infile);
+
+      c = read_skip_spaces (infile);
+      if (c != ')')
+	fatal_expected_char (infile, ')', c);
+
+      add_c_test (expr, value);
+    }
+  c = read_skip_spaces (infile);
+  if (c != ')')
+    fatal_expected_char (infile, ')', c);
+}
 
 static void
 validate_const_int (FILE *infile, const char *string)
@@ -1354,16 +1408,23 @@ read_rtx (FILE *infile, rtx *x, int *lineno)
     {
       struct map_value *mode_maps;
       struct macro_traverse_data mtd;
+      rtx from_file;
 
       c = read_skip_spaces (infile);
       if (c == EOF)
 	return false;
       ungetc (c, infile);
 
-      queue_next = queue_head;
       queue_lineno = read_rtx_lineno;
       mode_maps = 0;
-      XEXP (queue_next, 0) = read_rtx_1 (infile, &mode_maps);
+      from_file = read_rtx_1 (infile, &mode_maps);
+      if (from_file == 0)
+	return false;  /* This confuses a top level (nil) with end of
+			  file, but a top level (nil) would have
+			  crashed our caller anyway.  */
+
+      queue_next = queue_head;
+      XEXP (queue_next, 0) = from_file;
       XEXP (queue_next, 1) = 0;
 
       mtd.queue = queue_next;
@@ -1412,6 +1473,10 @@ read_rtx_1 (FILE *infile, struct map_value **mode_maps)
 
  again:
   c = read_skip_spaces (infile); /* Should be open paren.  */
+
+  if (c == EOF)
+    return 0;
+  
   if (c != '(')
     fatal_expected_char (infile, '(', c);
 
@@ -1429,6 +1494,11 @@ read_rtx_1 (FILE *infile, struct map_value **mode_maps)
       read_constants (infile, tmp_char);
       goto again;
     }
+  if (strcmp (tmp_char, "define_conditions") == 0)
+    {
+      read_conditions (infile, tmp_char);
+      goto again;
+    }
   if (strcmp (tmp_char, "define_mode_attr") == 0)
     {
       read_mapping (&modes, modes.attrs, infile);
-- 
GitLab