OSDN Git Service

2010-04-27 Jonathan Wakely <jwakely.gcc@gmail.com>
[pf3gnuchains/gcc-fork.git] / gcc / gensupport.c
index 115a178..74b1d25 100644 (file)
@@ -1,12 +1,12 @@
 /* Support routines for the various generation passes.
 /* Support routines for the various generation passes.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004
-   Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+   2010, 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
 
    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)
+   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 later version.
 
    GCC is distributed in the hope that it will be useful, but WITHOUT
@@ -15,9 +15,8 @@
    License for more details.
 
    You should have received a copy of the GNU General Public License
    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, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 #include "bconfig.h"
 #include "system.h"
 
 #include "bconfig.h"
 #include "system.h"
@@ -35,6 +34,12 @@ int target_flags;
 
 int insn_elision = 1;
 
 
 int insn_elision = 1;
 
+const char *in_fname;
+
+/* This callback will be invoked whenever an rtl include directive is
+   processed.  To be used for creation of the dependency file.  */
+void (*include_callback) (const char *);
+
 static struct obstack obstack;
 struct obstack *rtl_obstack = &obstack;
 
 static struct obstack obstack;
 struct obstack *rtl_obstack = &obstack;
 
@@ -65,6 +70,8 @@ struct queue_elem
 
 static struct queue_elem *define_attr_queue;
 static struct queue_elem **define_attr_tail = &define_attr_queue;
 
 static struct queue_elem *define_attr_queue;
 static struct queue_elem **define_attr_tail = &define_attr_queue;
+static struct queue_elem *define_pred_queue;
+static struct queue_elem **define_pred_tail = &define_pred_queue;
 static struct queue_elem *define_insn_queue;
 static struct queue_elem **define_insn_tail = &define_insn_queue;
 static struct queue_elem *define_cond_exec_queue;
 static struct queue_elem *define_insn_queue;
 static struct queue_elem **define_insn_tail = &define_insn_queue;
 static struct queue_elem *define_cond_exec_queue;
@@ -109,6 +116,8 @@ static void process_one_cond_exec (struct queue_elem *);
 static void process_define_cond_exec (void);
 static void process_include (rtx, int);
 static char *save_string (const char *, int);
 static void process_define_cond_exec (void);
 static void process_include (rtx, int);
 static char *save_string (const char *, int);
+static void init_predicate_table (void);
+static void record_insn_name (int, const char *);
 \f
 void
 message_with_line (int lineno, const char *msg, ...)
 \f
 void
 message_with_line (int lineno, const char *msg, ...)
@@ -128,7 +137,7 @@ message_with_line (int lineno, const char *msg, ...)
    the gensupport programs.  */
 
 rtx
    the gensupport programs.  */
 
 rtx
-gen_rtx_CONST_INT (enum machine_mode mode ATTRIBUTE_UNUSED,
+gen_rtx_CONST_INT (enum machine_mode ARG_UNUSED (mode),
                   HOST_WIDE_INT arg)
 {
   rtx rt = rtx_alloc (CONST_INT);
                   HOST_WIDE_INT arg)
 {
   rtx rt = rtx_alloc (CONST_INT);
@@ -144,7 +153,7 @@ static struct queue_elem *
 queue_pattern (rtx pattern, struct queue_elem ***list_tail,
               const char *filename, int lineno)
 {
 queue_pattern (rtx pattern, struct queue_elem ***list_tail,
               const char *filename, int lineno)
 {
-  struct queue_elem *e = xmalloc (sizeof (*e));
+  struct queue_elem *e = XNEW(struct queue_elem);
   e->data = pattern;
   e->filename = filename;
   e->lineno = lineno;
   e->data = pattern;
   e->filename = filename;
   e->lineno = lineno;
@@ -240,21 +249,12 @@ process_include (rtx desc, int lineno)
   read_rtx_filename = pathname;
   read_rtx_lineno = 1;
 
   read_rtx_filename = pathname;
   read_rtx_lineno = 1;
 
-  /* Read the entire file.  */
-  while (1)
-    {
-      rtx desc;
-      int c;
-
-      c = read_skip_spaces (input_file);
-      if (c == EOF)
-       break;
+  if (include_callback)
+    include_callback (pathname);
 
 
-      ungetc (c, input_file);
-      lineno = read_rtx_lineno;
-      desc = read_rtx (input_file);
-      process_rtx (desc, lineno);
-    }
+  /* Read the entire file.  */
+  while (read_rtx (input_file, &desc, &lineno))
+    process_rtx (desc, lineno);
 
   /* Do not free pathname.  It is attached to the various rtx queue
      elements.  */
 
   /* Do not free pathname.  It is attached to the various rtx queue
      elements.  */
@@ -284,6 +284,15 @@ process_rtx (rtx desc, int lineno)
       queue_pattern (desc, &define_attr_tail, read_rtx_filename, lineno);
       break;
 
       queue_pattern (desc, &define_attr_tail, read_rtx_filename, lineno);
       break;
 
+    case DEFINE_PREDICATE:
+    case DEFINE_SPECIAL_PREDICATE:
+    case DEFINE_CONSTRAINT:
+    case DEFINE_REGISTER_CONSTRAINT:
+    case DEFINE_MEMORY_CONSTRAINT:
+    case DEFINE_ADDRESS_CONSTRAINT:
+      queue_pattern (desc, &define_pred_tail, read_rtx_filename, lineno);
+      break;
+
     case INCLUDE:
       process_include (desc, lineno);
       break;
     case INCLUDE:
       process_include (desc, lineno);
       break;
@@ -312,7 +321,10 @@ process_rtx (rtx desc, int lineno)
           insn condition to create the new split condition.  */
        split_cond = XSTR (desc, 4);
        if (split_cond[0] == '&' && split_cond[1] == '&')
           insn condition to create the new split condition.  */
        split_cond = XSTR (desc, 4);
        if (split_cond[0] == '&' && split_cond[1] == '&')
-         split_cond = concat (XSTR (desc, 2), split_cond, NULL);
+         {
+           copy_rtx_ptr_loc (split_cond + 2, split_cond);
+           split_cond = join_c_conditions (XSTR (desc, 2), split_cond + 2);
+         }
        XSTR (split, 1) = split_cond;
        XVEC (split, 2) = XVEC (desc, 5);
        XSTR (split, 3) = XSTR (desc, 6);
        XSTR (split, 1) = split_cond;
        XVEC (split, 2) = XVEC (desc, 5);
        XSTR (split, 3) = XSTR (desc, 6);
@@ -324,7 +336,7 @@ process_rtx (rtx desc, int lineno)
 
        /* Queue them.  */
        insn_elem
 
        /* Queue them.  */
        insn_elem
-         = queue_pattern (desc, &define_insn_tail, read_rtx_filename, 
+         = queue_pattern (desc, &define_insn_tail, read_rtx_filename,
                           lineno);
        split_elem
          = queue_pattern (split, &other_tail, read_rtx_filename, lineno);
                           lineno);
        split_elem
          = queue_pattern (split, &other_tail, read_rtx_filename, lineno);
@@ -394,7 +406,7 @@ is_predicable (struct queue_elem *elem)
          return 0;
 
        default:
          return 0;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
 
        }
     }
 
@@ -455,6 +467,8 @@ identify_predicable_attribute (void)
       message_with_line (elem->lineno,
                         "attribute `predicable' is not a boolean");
       errors = 1;
       message_with_line (elem->lineno,
                         "attribute `predicable' is not a boolean");
       errors = 1;
+      if (p_false)
+        free (p_false);
       return;
     }
   p_true[-1] = '\0';
       return;
     }
   p_true[-1] = '\0';
@@ -472,12 +486,16 @@ identify_predicable_attribute (void)
       message_with_line (elem->lineno,
                         "attribute `predicable' cannot be const");
       errors = 1;
       message_with_line (elem->lineno,
                         "attribute `predicable' cannot be const");
       errors = 1;
+      if (p_false)
+       free (p_false);
       return;
 
     default:
       message_with_line (elem->lineno,
                         "attribute `predicable' must have a constant default");
       errors = 1;
       return;
 
     default:
       message_with_line (elem->lineno,
                         "attribute `predicable' must have a constant default");
       errors = 1;
+      if (p_false)
+       free (p_false);
       return;
     }
 
       return;
     }
 
@@ -491,6 +509,8 @@ identify_predicable_attribute (void)
                         "unknown value `%s' for `predicable' attribute",
                         value);
       errors = 1;
                         "unknown value `%s' for `predicable' attribute",
                         value);
       errors = 1;
+      if (p_false)
+       free (p_false);
     }
 }
 
     }
 }
 
@@ -561,7 +581,7 @@ collect_insn_data (rtx pattern, int *palt, int *pmax)
          break;
 
        default:
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
 }
        }
     }
 }
@@ -594,7 +614,7 @@ alter_predicate_for_insn (rtx pattern, int alt, int max_op, int lineno)
          {
            size_t c_len = strlen (c);
            size_t len = alt * (c_len + 1);
          {
            size_t c_len = strlen (c);
            size_t len = alt * (c_len + 1);
-           char *new_c = xmalloc (len);
+           char *new_c = XNEWVEC(char, len);
 
            memcpy (new_c, c, c_len);
            for (i = 1; i < alt; ++i)
 
            memcpy (new_c, c, c_len);
            for (i = 1; i < alt; ++i)
@@ -647,7 +667,7 @@ alter_predicate_for_insn (rtx pattern, int alt, int max_op, int lineno)
          break;
 
        default:
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
 
        }
     }
 
@@ -658,44 +678,36 @@ static const char *
 alter_test_for_insn (struct queue_elem *ce_elem,
                     struct queue_elem *insn_elem)
 {
 alter_test_for_insn (struct queue_elem *ce_elem,
                     struct queue_elem *insn_elem)
 {
-  const char *ce_test, *insn_test;
-
-  ce_test = XSTR (ce_elem->data, 1);
-  insn_test = XSTR (insn_elem->data, 2);
-  if (!ce_test || *ce_test == '\0')
-    return insn_test;
-  if (!insn_test || *insn_test == '\0')
-    return ce_test;
-
-  return concat ("(", ce_test, ") && (", insn_test, ")", NULL);
+  return join_c_conditions (XSTR (ce_elem->data, 1),
+                           XSTR (insn_elem->data, 2));
 }
 
 }
 
-/* Adjust all of the operand numbers in OLD to match the shift they'll
+/* Adjust all of the operand numbers in SRC to match the shift they'll
    get from an operand displacement of DISP.  Return a pointer after the
    adjusted string.  */
 
 static char *
    get from an operand displacement of DISP.  Return a pointer after the
    adjusted string.  */
 
 static char *
-shift_output_template (char *new, const char *old, int disp)
+shift_output_template (char *dest, const char *src, int disp)
 {
 {
-  while (*old)
+  while (*src)
     {
     {
-      char c = *old++;
-      *new++ = c;
+      char c = *src++;
+      *dest++ = c;
       if (c == '%')
        {
       if (c == '%')
        {
-         c = *old++;
+         c = *src++;
          if (ISDIGIT ((unsigned char) c))
            c += disp;
          else if (ISALPHA (c))
            {
          if (ISDIGIT ((unsigned char) c))
            c += disp;
          else if (ISALPHA (c))
            {
-             *new++ = c;
-             c = *old++ + disp;
+             *dest++ = c;
+             c = *src++ + disp;
            }
            }
-         *new++ = c;
+         *dest++ = c;
        }
     }
 
        }
     }
 
-  return new;
+  return dest;
 }
 
 static const char *
 }
 
 static const char *
@@ -704,7 +716,7 @@ alter_output_for_insn (struct queue_elem *ce_elem,
                       int alt, int max_op)
 {
   const char *ce_out, *insn_out;
                       int alt, int max_op)
 {
   const char *ce_out, *insn_out;
-  char *new, *p;
+  char *result, *p;
   size_t len, ce_len, insn_len;
 
   /* ??? Could coordinate with genoutput to not duplicate code here.  */
   size_t len, ce_len, insn_len;
 
   /* ??? Could coordinate with genoutput to not duplicate code here.  */
@@ -724,7 +736,7 @@ alter_output_for_insn (struct queue_elem *ce_elem,
   if (*insn_out == '@')
     {
       len = (ce_len + 1) * alt + insn_len + 1;
   if (*insn_out == '@')
     {
       len = (ce_len + 1) * alt + insn_len + 1;
-      p = new = xmalloc (len);
+      p = result = XNEWVEC(char, len);
 
       do
        {
 
       do
        {
@@ -748,14 +760,14 @@ alter_output_for_insn (struct queue_elem *ce_elem,
   else
     {
       len = ce_len + 1 + insn_len + 1;
   else
     {
       len = ce_len + 1 + insn_len + 1;
-      new = xmalloc (len);
+      result = XNEWVEC (char, len);
 
 
-      p = shift_output_template (new, ce_out, max_op);
+      p = shift_output_template (result, ce_out, max_op);
       *p++ = ' ';
       memcpy (p, insn_out, insn_len + 1);
     }
 
       *p++ = ' ';
       memcpy (p, insn_out, insn_len + 1);
     }
 
-  return new;
+  return result;
 }
 
 /* Replicate insns as appropriate for the given DEFINE_COND_EXEC.  */
 }
 
 /* Replicate insns as appropriate for the given DEFINE_COND_EXEC.  */
@@ -768,6 +780,7 @@ process_one_cond_exec (struct queue_elem *ce_elem)
     {
       int alternatives, max_operand;
       rtx pred, insn, pattern, split;
     {
       int alternatives, max_operand;
       rtx pred, insn, pattern, split;
+      char *new_name;
       int i;
 
       if (! is_predicable (insn_elem))
       int i;
 
       if (! is_predicable (insn_elem))
@@ -794,7 +807,9 @@ process_one_cond_exec (struct queue_elem *ce_elem)
 
       /* Construct a new pattern for the new insn.  */
       insn = copy_rtx (insn_elem->data);
 
       /* Construct a new pattern for the new insn.  */
       insn = copy_rtx (insn_elem->data);
-      XSTR (insn, 0) = "";
+      new_name = XNEWVAR (char, strlen XSTR (insn_elem->data, 0) + 4);
+      sprintf (new_name, "*p %s", XSTR (insn_elem->data, 0));
+      XSTR (insn, 0) = new_name;
       pattern = rtx_alloc (COND_EXEC);
       XEXP (pattern, 0) = pred;
       if (XVECLEN (insn, 1) == 1)
       pattern = rtx_alloc (COND_EXEC);
       XEXP (pattern, 0) = pred;
       if (XVECLEN (insn, 1) == 1)
@@ -863,7 +878,7 @@ process_one_cond_exec (struct queue_elem *ce_elem)
          XVECEXP (split, 2, i) = pattern;
        }
       /* Add the new split to the queue.  */
          XVECEXP (split, 2, i) = pattern;
        }
       /* Add the new split to the queue.  */
-      queue_pattern (split, &other_tail, read_rtx_filename, 
+      queue_pattern (split, &other_tail, read_rtx_filename,
                     insn_elem->split->lineno);
     }
 }
                     insn_elem->split->lineno);
     }
 }
@@ -887,7 +902,7 @@ process_define_cond_exec (void)
 static char *
 save_string (const char *s, int len)
 {
 static char *
 save_string (const char *s, int len)
 {
-  char *result = xmalloc (len + 1);
+  char *result = XNEWVEC (char, len + 1);
 
   memcpy (result, s, len);
   result[len] = 0;
 
   memcpy (result, s, len);
   result[len] = 0;
@@ -898,105 +913,151 @@ save_string (const char *s, int len)
 /* The entry point for initializing the reader.  */
 
 int
 /* The entry point for initializing the reader.  */
 
 int
-init_md_reader_args (int argc, char **argv)
+init_md_reader_args_cb (int argc, char **argv, bool (*parse_opt)(const char *))
 {
 {
-  int i;
-  const char *in_fname;
+  FILE *input_file;
+  int c, i, lineno;
+  char *lastsl;
+  rtx desc;
+  bool no_more_options;
+  bool already_read_stdin;
 
 
-  max_include_len = 0;
-  in_fname = NULL;
+  /* Unlock the stdio streams.  */
+  unlock_std_streams ();
+
+  /* First we loop over all the options.  */
   for (i = 1; i < argc; i++)
     {
       if (argv[i][0] != '-')
   for (i = 1; i < argc; i++)
     {
       if (argv[i][0] != '-')
+       continue;
+
+      c = argv[i][1];
+      switch (c)
        {
        {
-         if (in_fname == NULL)
-           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 = xmalloc (sizeof (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:
-             fatal ("invalid option `%s'", argv[i]);
+       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;
 
 
-           }
-       }
-    }
-    return init_md_reader (in_fname);
-}
-\f
-/* The entry point for initializing the reader.  */
+       case '\0':
+         /* An argument consisting of exactly one dash is a request to
+            read stdin.  This will be handled in the second loop.  */
+         continue;
 
 
-int
-init_md_reader (const char *filename)
-{
-  FILE *input_file;
-  int c;
-  size_t i;
-  char *lastsl;
+       case '-':
+         /* An argument consisting of just two dashes causes option
+            parsing to cease.  */
+         if (argv[i][2] == '\0')
+           goto stop_parsing_options;
 
 
-  lastsl = strrchr (filename, '/');
-  if (lastsl != NULL)
-    base_dir = save_string (filename, lastsl - filename + 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 = filename;
-  input_file = fopen (filename, "r");
-  if (input_file == 0)
-    {
-      perror (filename);
-      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 (i = 0; i < n_insn_conditions; i++)
-    *(htab_find_slot (condition_table, &insn_conditions[i], INSERT))
-      = (void *) &insn_conditions[i];
+ 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;
   obstack_init (rtl_obstack);
   errors = 0;
   sequence_num = 0;
+  no_more_options = false;
+  already_read_stdin = false;
 
 
-  /* Read the entire file.  */
-  while (1)
+
+  /* Now loop over all input files.  */
+  for (i = 1; i < argc; i++)
     {
     {
-      rtx desc;
-      int lineno;
+      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;
+       }
 
 
-      c = read_skip_spaces (input_file);
-      if (c == EOF)
-        break;
+      /* If we get here we are looking at a non-option argument, i.e.
+        a file to be processed.  */
 
 
-      ungetc (c, input_file);
-      lineno = read_rtx_lineno;
-      desc = read_rtx (input_file);
-      process_rtx (desc, lineno);
+      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);
     }
     }
-  fclose (input_file);
 
   /* Process define_cond_exec patterns.  */
   if (define_cond_exec_queue != NULL)
 
   /* Process define_cond_exec patterns.  */
   if (define_cond_exec_queue != NULL)
@@ -1005,6 +1066,14 @@ init_md_reader (const char *filename)
   return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
 }
 
   return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
 }
 
+/* Programs that don't have their own options can use this entry point
+   instead.  */
+int
+init_md_reader_args (int argc, char **argv)
+{
+  return init_md_reader_args_cb (argc, argv, 0);
+}
+\f
 /* The entry point for reading a single rtx from an md file.  */
 
 rtx
 /* The entry point for reading a single rtx from an md file.  */
 
 rtx
@@ -1018,6 +1087,8 @@ read_md_rtx (int *lineno, int *seqnr)
   /* Read all patterns from a given queue before moving on to the next.  */
   if (define_attr_queue != NULL)
     queue = &define_attr_queue;
   /* Read all patterns from a given queue before moving on to the next.  */
   if (define_attr_queue != NULL)
     queue = &define_attr_queue;
+  else if (define_pred_queue != NULL)
+    queue = &define_pred_queue;
   else if (define_insn_queue != NULL)
     queue = &define_insn_queue;
   else if (other_queue != NULL)
   else if (define_insn_queue != NULL)
     queue = &define_insn_queue;
   else if (other_queue != NULL)
@@ -1048,6 +1119,10 @@ read_md_rtx (int *lineno, int *seqnr)
        sequence_num++;
       else if (insn_elision)
        goto discard;
        sequence_num++;
       else if (insn_elision)
        goto discard;
+
+      /* *seqnr is used here so the name table will match caller's
+        idea of insn numbering, whether or not elision is active.  */
+      record_insn_name (*seqnr, XSTR (desc, 0));
       break;
 
     case DEFINE_SPLIT:
       break;
 
     case DEFINE_SPLIT:
@@ -1118,17 +1193,41 @@ maybe_eval_c_test (const char *expr)
   if (expr[0] == 0)
     return 1;
 
   if (expr[0] == 0)
     return 1;
 
-  if (insn_elision_unavailable)
-    return -1;
-
   dummy.expr = expr;
   dummy.expr = expr;
-  test = htab_find (condition_table, &dummy);
+  test = (const struct c_test *)htab_find (condition_table, &dummy);
   if (!test)
   if (!test)
-    abort ();
-
+    return -1;
   return test->value;
 }
 
   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
 /* Given a string, return the number of comma-separated elements in it.
    Return 0 for the null string.  */
 int
@@ -1174,3 +1273,189 @@ scan_comma_elt (const char **pstr)
   *pstr = p;
   return start;
 }
   *pstr = p;
   return start;
 }
+
+/* Helper functions for define_predicate and define_special_predicate
+   processing.  Shared between genrecog.c and genpreds.c.  */
+
+static htab_t predicate_table;
+struct pred_data *first_predicate;
+static struct pred_data **last_predicate = &first_predicate;
+
+static hashval_t
+hash_struct_pred_data (const void *ptr)
+{
+  return htab_hash_string (((const struct pred_data *)ptr)->name);
+}
+
+static int
+eq_struct_pred_data (const void *a, const void *b)
+{
+  return !strcmp (((const struct pred_data *)a)->name,
+                 ((const struct pred_data *)b)->name);
+}
+
+struct pred_data *
+lookup_predicate (const char *name)
+{
+  struct pred_data key;
+  key.name = name;
+  return (struct pred_data *) htab_find (predicate_table, &key);
+}
+
+/* Record that predicate PRED can accept CODE.  */
+
+void
+add_predicate_code (struct pred_data *pred, enum rtx_code code)
+{
+  if (!pred->codes[code])
+    {
+      pred->num_codes++;
+      pred->codes[code] = true;
+
+      if (GET_RTX_CLASS (code) != RTX_CONST_OBJ)
+       pred->allows_non_const = true;
+
+      if (code != REG
+         && code != SUBREG
+         && code != MEM
+         && code != CONCAT
+         && code != PARALLEL
+         && code != STRICT_LOW_PART)
+       pred->allows_non_lvalue = true;
+
+      if (pred->num_codes == 1)
+       pred->singleton = code;
+      else if (pred->num_codes == 2)
+       pred->singleton = UNKNOWN;
+    }
+}
+
+void
+add_predicate (struct pred_data *pred)
+{
+  void **slot = htab_find_slot (predicate_table, pred, INSERT);
+  if (*slot)
+    {
+      error ("duplicate predicate definition for '%s'", pred->name);
+      return;
+    }
+  *slot = pred;
+  *last_predicate = pred;
+  last_predicate = &pred->next;
+}
+
+/* This array gives the initial content of the predicate table.  It
+   has entries for all predicates defined in recog.c.  */
+
+struct std_pred_table
+{
+  const char *name;
+  bool special;
+  bool allows_const_p;
+  RTX_CODE codes[NUM_RTX_CODE];
+};
+
+static const struct std_pred_table std_preds[] = {
+  {"general_operand", false, true, {SUBREG, REG, MEM}},
+  {"address_operand", true, true, {SUBREG, REG, MEM, PLUS, MINUS, MULT}},
+  {"register_operand", false, false, {SUBREG, REG}},
+  {"pmode_register_operand", true, false, {SUBREG, REG}},
+  {"scratch_operand", false, false, {SCRATCH, REG}},
+  {"immediate_operand", false, true, {UNKNOWN}},
+  {"const_int_operand", false, false, {CONST_INT}},
+  {"const_double_operand", false, false, {CONST_INT, CONST_DOUBLE}},
+  {"nonimmediate_operand", false, false, {SUBREG, REG, MEM}},
+  {"nonmemory_operand", false, true, {SUBREG, REG}},
+  {"push_operand", false, false, {MEM}},
+  {"pop_operand", false, false, {MEM}},
+  {"memory_operand", false, false, {SUBREG, MEM}},
+  {"indirect_operand", false, false, {SUBREG, MEM}},
+  {"ordered_comparison_operator", false, false, {EQ, NE,
+                                                LE, LT, GE, GT,
+                                                LEU, LTU, GEU, GTU}},
+  {"comparison_operator", false, false, {EQ, NE,
+                                        LE, LT, GE, GT,
+                                        LEU, LTU, GEU, GTU,
+                                        UNORDERED, ORDERED,
+                                        UNEQ, UNGE, UNGT,
+                                        UNLE, UNLT, LTGT}}
+};
+#define NUM_KNOWN_STD_PREDS ARRAY_SIZE (std_preds)
+
+/* Initialize the table of predicate definitions, starting with
+   the information we have on generic predicates.  */
+
+static void
+init_predicate_table (void)
+{
+  size_t i, j;
+  struct pred_data *pred;
+
+  predicate_table = htab_create_alloc (37, hash_struct_pred_data,
+                                      eq_struct_pred_data, 0,
+                                      xcalloc, free);
+
+  for (i = 0; i < NUM_KNOWN_STD_PREDS; i++)
+    {
+      pred = XCNEW (struct pred_data);
+      pred->name = std_preds[i].name;
+      pred->special = std_preds[i].special;
+
+      for (j = 0; std_preds[i].codes[j] != 0; j++)
+       add_predicate_code (pred, std_preds[i].codes[j]);
+
+      if (std_preds[i].allows_const_p)
+       for (j = 0; j < NUM_RTX_CODE; j++)
+         if (GET_RTX_CLASS (j) == RTX_CONST_OBJ)
+           add_predicate_code (pred, (enum rtx_code) j);
+
+      add_predicate (pred);
+    }
+}
+\f
+/* These functions allow linkage with print-rtl.c.  Also, some generators
+   like to annotate their output with insn names.  */
+
+/* Holds an array of names indexed by insn_code_number.  */
+static char **insn_name_ptr = 0;
+static int insn_name_ptr_size = 0;
+
+const char *
+get_insn_name (int code)
+{
+  if (code < insn_name_ptr_size)
+    return insn_name_ptr[code];
+  else
+    return NULL;
+}
+
+static void
+record_insn_name (int code, const char *name)
+{
+  static const char *last_real_name = "insn";
+  static int last_real_code = 0;
+  char *new_name;
+
+  if (insn_name_ptr_size <= code)
+    {
+      int new_size;
+      new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
+      insn_name_ptr = XRESIZEVEC (char *, insn_name_ptr, new_size);
+      memset (insn_name_ptr + insn_name_ptr_size, 0,
+             sizeof(char *) * (new_size - insn_name_ptr_size));
+      insn_name_ptr_size = new_size;
+    }
+
+  if (!name || name[0] == '\0')
+    {
+      new_name = XNEWVAR (char, strlen (last_real_name) + 10);
+      sprintf (new_name, "%s+%d", last_real_name, code - last_real_code);
+    }
+  else
+    {
+      last_real_name = new_name = xstrdup (name);
+      last_real_code = code;
+    }
+
+  insn_name_ptr[code] = new_name;
+}