]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/genrecog.c
PR fortran/95090 - ICE: identifier overflow
[thirdparty/gcc.git] / gcc / genrecog.c
index e152b3414080e4ef20a332d498741283e5fadc71..bc371b1903c65197dc5c42e0f5b655041dc260d7 100644 (file)
@@ -1,5 +1,5 @@
 /* Generate code from machine description to recognize rtl as insns.
-   Copyright (C) 1987-2015 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
    5. Write out C++ code for each function.  */
 
 #include "bconfig.h"
+#define INCLUDE_ALGORITHM
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
 #include "errors.h"
 #include "read-md.h"
 #include "gensupport.h"
-#include "hash-table.h"
-#include "inchash.h"
-#include <algorithm>
 
 #undef GENERATOR_FILE
 enum true_rtx_doe {
@@ -172,17 +170,17 @@ static const bool force_unique_params_p = true;
 /* The maximum (approximate) depth of block nesting that an individual
    routine or subroutine should have.  This limit is about keeping the
    output readable rather than reducing compile time.  */
-static const int MAX_DEPTH = 6;
+static const unsigned int MAX_DEPTH = 6;
 
 /* The minimum number of pseudo-statements that a state must have before
    we split it out into a subroutine.  */
-static const int MIN_NUM_STATEMENTS = 5;
+static const unsigned int MIN_NUM_STATEMENTS = 5;
 
 /* The number of pseudo-statements a state can have before we consider
    splitting out substates into subroutines.  This limit is about avoiding
    compile-time problems with very big functions (and also about keeping
    functions within --param optimization limits, etc.).  */
-static const int MAX_NUM_STATEMENTS = 200;
+static const unsigned int MAX_NUM_STATEMENTS = 200;
 
 /* The minimum number of pseudo-statements that can be used in a pattern
    routine.  */
@@ -252,12 +250,6 @@ enum routine_type {
   SUBPATTERN, RECOG, SPLIT, PEEPHOLE2
 };
 
-/* Next number to use as an insn_code.  */
-static int next_insn_code;
-
-/* The line number of the start of the pattern currently being processed.  */
-static int pattern_lineno;
-
 /* The root position (x0).  */
 static struct position root_pos;
 
@@ -396,7 +388,7 @@ find_operand (rtx pattern, int n, rtx stop)
              return r;
          break;
 
-       case 'i': case 'w': case '0': case 's':
+       case 'r': case 'p': case 'i': case 'w': case '0': case 's':
          break;
 
        default:
@@ -447,7 +439,7 @@ find_matching_operand (rtx pattern, int n)
              return r;
          break;
 
-       case 'i': case 'w': case '0': case 's':
+       case 'r': case 'p': case 'i': case 'w': case '0': case 's':
          break;
 
        default:
@@ -471,12 +463,45 @@ constraints_supported_in_insn_p (rtx insn)
           || GET_CODE (insn) == DEFINE_PEEPHOLE2);
 }
 
-/* Check for various errors in patterns.  SET is nonnull for a destination,
-   and is the complete set pattern.  SET_CODE is '=' for normal sets, and
-   '+' within a context that requires in-out constraints.  */
+/* Return the name of the predicate matched by MATCH_RTX.  */
+
+static const char *
+predicate_name (rtx match_rtx)
+{
+  if (GET_CODE (match_rtx) == MATCH_SCRATCH)
+    return "scratch_operand";
+  else
+    return XSTR (match_rtx, 1);
+}
+
+/* Return true if OPERAND is a MATCH_OPERAND using a special predicate
+   function.  */
+
+static bool
+special_predicate_operand_p (rtx operand)
+{
+  if (GET_CODE (operand) == MATCH_OPERAND)
+    {
+      const char *pred_name = predicate_name (operand);
+      if (pred_name[0] != 0)
+       {
+         const struct pred_data *pred;
+
+         pred = lookup_predicate (pred_name);
+         return pred != NULL && pred->special;
+       }
+    }
+
+  return false;
+}
+
+/* Check for various errors in PATTERN, which is part of INFO.
+   SET is nonnull for a destination, and is the complete set pattern.
+   SET_CODE is '=' for normal sets, and '+' within a context that
+   requires in-out constraints.  */
 
 static void
-validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
+validate_pattern (rtx pattern, md_rtx_info *info, rtx set, int set_code)
 {
   const char *fmt;
   RTX_CODE code;
@@ -490,13 +515,12 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
       {
        const char constraints0 = XSTR (pattern, 1)[0];
 
-       if (!constraints_supported_in_insn_p (insn))
+       if (!constraints_supported_in_insn_p (info->def))
          {
            if (constraints0)
              {
-               error_with_line (pattern_lineno,
-                                "constraints not supported in %s",
-                                rtx_name[GET_CODE (insn)]);
+               error_at (info->loc, "constraints not supported in %s",
+                         GET_RTX_NAME (GET_CODE (info->def)));
              }
            return;
          }
@@ -508,19 +532,17 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
            && constraints0 != '='
            && constraints0 != '+')
          {
-           error_with_line (pattern_lineno,
-                            "operand %d missing output reload",
-                            XINT (pattern, 0));
+           error_at (info->loc, "operand %d missing output reload",
+                     XINT (pattern, 0));
          }
        return;
       }
     case MATCH_DUP:
     case MATCH_OP_DUP:
     case MATCH_PAR_DUP:
-      if (find_operand (insn, XINT (pattern, 0), pattern) == pattern)
-       error_with_line (pattern_lineno,
-                        "operand %i duplicated before defined",
-                        XINT (pattern, 0));
+      if (find_operand (info->def, XINT (pattern, 0), pattern) == pattern)
+       error_at (info->loc, "operand %i duplicated before defined",
+                 XINT (pattern, 0));
       break;
     case MATCH_OPERAND:
     case MATCH_OPERATOR:
@@ -529,17 +551,13 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
        const struct pred_data *pred;
        const char *c_test;
 
-       if (GET_CODE (insn) == DEFINE_INSN)
-         c_test = XSTR (insn, 2);
-       else
-         c_test = XSTR (insn, 1);
+       c_test = get_c_test (info->def);
 
        if (pred_name[0] != 0)
          {
            pred = lookup_predicate (pred_name);
            if (!pred)
-             error_with_line (pattern_lineno, "unknown predicate '%s'",
-                              pred_name);
+             error_at (info->loc, "unknown predicate '%s'", pred_name);
          }
        else
          pred = 0;
@@ -549,13 +567,12 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
            const char *constraints = XSTR (pattern, 2);
            const char constraints0 = constraints[0];
 
-           if (!constraints_supported_in_insn_p (insn))
+           if (!constraints_supported_in_insn_p (info->def))
              {
                if (constraints0)
                  {
-                   error_with_line (pattern_lineno,
-                                    "constraints not supported in %s",
-                                    rtx_name[GET_CODE (insn)]);
+                   error_at (info->loc, "constraints not supported in %s",
+                             GET_RTX_NAME (GET_CODE (info->def)));
                  }
              }
 
@@ -569,17 +586,16 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
                    /* If we've only got an output reload for this operand,
                       we'd better have a matching input operand.  */
                    else if (constraints0 == '='
-                            && find_matching_operand (insn, XINT (pattern, 0)))
+                            && find_matching_operand (info->def,
+                                                      XINT (pattern, 0)))
                      ;
                    else
-                     error_with_line (pattern_lineno,
-                                      "operand %d missing in-out reload",
-                                      XINT (pattern, 0));
+                     error_at (info->loc, "operand %d missing in-out reload",
+                               XINT (pattern, 0));
                  }
                else if (constraints0 != '=' && constraints0 != '+')
-                 error_with_line (pattern_lineno,
-                                  "operand %d missing output reload",
-                                  XINT (pattern, 0));
+                 error_at (info->loc, "operand %d missing output reload",
+                           XINT (pattern, 0));
              }
 
            /* For matching constraint in MATCH_OPERAND, the digit must be a
@@ -599,10 +615,9 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
 
                    sscanf (constraints, "%d", &val);
                    if (val >= XINT (pattern, 0))
-                     error_with_line (pattern_lineno,
-                                      "constraint digit %d is not smaller than"
-                                      " operand %d",
-                                      val, XINT (pattern, 0));
+                     error_at (info->loc, "constraint digit %d is not"
+                               " smaller than operand %d",
+                               val, XINT (pattern, 0));
                  }
 
                while (constraints[0] && constraints[0] != ',')
@@ -614,9 +629,8 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
           while not likely to occur at runtime, results in less efficient
           code from insn-recog.c.  */
        if (set && pred && pred->allows_non_lvalue)
-         error_with_line (pattern_lineno,
-                          "destination operand %d allows non-lvalue",
-                          XINT (pattern, 0));
+         error_at (info->loc, "destination operand %d allows non-lvalue",
+                   XINT (pattern, 0));
 
        /* A modeless MATCH_OPERAND can be handy when we can check for
           multiple modes in the c_test.  In most other cases, it is a
@@ -628,7 +642,7 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
 
        if (GET_MODE (pattern) == VOIDmode
            && code == MATCH_OPERAND
-           && GET_CODE (insn) == DEFINE_INSN
+           && GET_CODE (info->def) == DEFINE_INSN
            && pred
            && !pred->special
            && pred->allows_non_const
@@ -636,9 +650,8 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
            && ! (set
                  && GET_CODE (set) == SET
                  && GET_CODE (SET_SRC (set)) == CALL))
-         message_with_line (pattern_lineno,
-                            "warning: operand %d missing mode?",
-                            XINT (pattern, 0));
+         message_at (info->loc, "warning: operand %d missing mode?",
+                     XINT (pattern, 0));
        return;
       }
 
@@ -660,28 +673,26 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
        if (GET_CODE (dest) == MATCH_DUP
            || GET_CODE (dest) == MATCH_OP_DUP
            || GET_CODE (dest) == MATCH_PAR_DUP)
-         dest = find_operand (insn, XINT (dest, 0), NULL);
+         dest = find_operand (info->def, XINT (dest, 0), NULL);
 
        if (GET_CODE (src) == MATCH_DUP
            || GET_CODE (src) == MATCH_OP_DUP
            || GET_CODE (src) == MATCH_PAR_DUP)
-         src = find_operand (insn, XINT (src, 0), NULL);
+         src = find_operand (info->def, XINT (src, 0), NULL);
 
        dmode = GET_MODE (dest);
        smode = GET_MODE (src);
 
-       /* The mode of an ADDRESS_OPERAND is the mode of the memory
-          reference, not the mode of the address.  */
-       if (GET_CODE (src) == MATCH_OPERAND
-           && ! strcmp (XSTR (src, 1), "address_operand"))
+       /* Mode checking is not performed for special predicates.  */
+       if (special_predicate_operand_p (src)
+           || special_predicate_operand_p (dest))
          ;
 
         /* The operands of a SET must have the same mode unless one
           is VOIDmode.  */
         else if (dmode != VOIDmode && smode != VOIDmode && dmode != smode)
-         error_with_line (pattern_lineno,
-                          "mode mismatch in set: %smode vs %smode",
-                          GET_MODE_NAME (dmode), GET_MODE_NAME (smode));
+         error_at (info->loc, "mode mismatch in set: %smode vs %smode",
+                   GET_MODE_NAME (dmode), GET_MODE_NAME (smode));
 
        /* If only one of the operands is VOIDmode, and PC or CC0 is
           not involved, it's probably a mistake.  */
@@ -696,36 +707,81 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
          {
            const char *which;
            which = (dmode == VOIDmode ? "destination" : "source");
-           message_with_line (pattern_lineno,
-                              "warning: %s missing a mode?", which);
+           message_at (info->loc, "warning: %s missing a mode?", which);
          }
 
        if (dest != SET_DEST (pattern))
-         validate_pattern (dest, insn, pattern, '=');
-       validate_pattern (SET_DEST (pattern), insn, pattern, '=');
-        validate_pattern (SET_SRC (pattern), insn, NULL_RTX, 0);
+         validate_pattern (dest, info, pattern, '=');
+       validate_pattern (SET_DEST (pattern), info, pattern, '=');
+        validate_pattern (SET_SRC (pattern), info, NULL_RTX, 0);
         return;
       }
 
     case CLOBBER:
-      validate_pattern (SET_DEST (pattern), insn, pattern, '=');
+      validate_pattern (SET_DEST (pattern), info, pattern, '=');
       return;
 
     case ZERO_EXTRACT:
-      validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
-      validate_pattern (XEXP (pattern, 1), insn, NULL_RTX, 0);
-      validate_pattern (XEXP (pattern, 2), insn, NULL_RTX, 0);
+      validate_pattern (XEXP (pattern, 0), info, set, set ? '+' : 0);
+      validate_pattern (XEXP (pattern, 1), info, NULL_RTX, 0);
+      validate_pattern (XEXP (pattern, 2), info, NULL_RTX, 0);
       return;
 
     case STRICT_LOW_PART:
-      validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
+      validate_pattern (XEXP (pattern, 0), info, set, set ? '+' : 0);
       return;
 
     case LABEL_REF:
-      if (GET_MODE (LABEL_REF_LABEL (pattern)) != VOIDmode)
-       error_with_line (pattern_lineno,
-                        "operand to label_ref %smode not VOIDmode",
-                        GET_MODE_NAME (GET_MODE (LABEL_REF_LABEL (pattern))));
+      if (GET_MODE (XEXP (pattern, 0)) != VOIDmode)
+       error_at (info->loc, "operand to label_ref %smode not VOIDmode",
+                 GET_MODE_NAME (GET_MODE (XEXP (pattern, 0))));
+      break;
+
+    case VEC_SELECT:
+      if (GET_MODE (pattern) != VOIDmode)
+       {
+         machine_mode mode = GET_MODE (pattern);
+         machine_mode imode = GET_MODE (XEXP (pattern, 0));
+         machine_mode emode
+           = VECTOR_MODE_P (mode) ? GET_MODE_INNER (mode) : mode;
+         if (GET_CODE (XEXP (pattern, 1)) == PARALLEL)
+           {
+             int expected = 1;
+             unsigned int nelems;
+             if (VECTOR_MODE_P (mode)
+                 && !GET_MODE_NUNITS (mode).is_constant (&expected))
+               error_at (info->loc,
+                         "vec_select with variable-sized mode %s",
+                         GET_MODE_NAME (mode));
+             else if (XVECLEN (XEXP (pattern, 1), 0) != expected)
+               error_at (info->loc,
+                         "vec_select parallel with %d elements, expected %d",
+                         XVECLEN (XEXP (pattern, 1), 0), expected);
+             else if (VECTOR_MODE_P (imode)
+                      && GET_MODE_NUNITS (imode).is_constant (&nelems))
+               {
+                 int i;
+                 for (i = 0; i < expected; ++i)
+                   if (CONST_INT_P (XVECEXP (XEXP (pattern, 1), 0, i))
+                       && (UINTVAL (XVECEXP (XEXP (pattern, 1), 0, i))
+                           >= nelems))
+                     error_at (info->loc,
+                               "out of bounds selector %u in vec_select, "
+                               "expected at most %u",
+                               (unsigned)
+                               UINTVAL (XVECEXP (XEXP (pattern, 1), 0, i)),
+                               nelems - 1);
+               }
+           }
+         if (imode != VOIDmode && !VECTOR_MODE_P (imode))
+           error_at (info->loc, "%smode of first vec_select operand is not a "
+                                "vector mode", GET_MODE_NAME (imode));
+         else if (imode != VOIDmode && GET_MODE_INNER (imode) != emode)
+           error_at (info->loc, "element mode mismatch between vec_select "
+                                "%smode and its operand %smode",
+                     GET_MODE_NAME (emode),
+                     GET_MODE_NAME (GET_MODE_INNER (imode)));
+       }
       break;
 
     default:
@@ -739,15 +795,15 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
       switch (fmt[i])
        {
        case 'e': case 'u':
-         validate_pattern (XEXP (pattern, i), insn, NULL_RTX, 0);
+         validate_pattern (XEXP (pattern, i), info, NULL_RTX, 0);
          break;
 
        case 'E':
          for (j = 0; j < XVECLEN (pattern, i); j++)
-           validate_pattern (XVECEXP (pattern, i, j), insn, NULL_RTX, 0);
+           validate_pattern (XVECEXP (pattern, i, j), info, NULL_RTX, 0);
          break;
 
-       case 'i': case 'w': case '0': case 's':
+       case 'r': case 'p': case 'i': case 'w': case '0': case 's':
          break;
 
        default:
@@ -761,11 +817,13 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
    to "T *prev, *next;" and a function "void set_parent (list_head <T> *)"
    to set the parent list.  */
 template <typename T>
-struct list_head
+class list_head
 {
+public:
   /* A range of linked items.  */
-  struct range
+  class range
   {
+  public:
     range (T *);
     range (T *, T *);
 
@@ -891,7 +949,7 @@ list_head <T>::singleton () const
   return first == last ? first : 0;
 }
 \f
-struct state;
+class state;
 
 /* Describes a possible successful return from a routine.  */
 struct acceptance_type
@@ -951,8 +1009,9 @@ operator != (const acceptance_type &a, const acceptance_type &b)
 }
 
 /* Represents a parameter to a pattern routine.  */
-struct parameter
+class parameter
 {
+public:
   /* The C type of parameter.  */
   enum type_enum {
     /* Represents an invalid parameter.  */
@@ -967,6 +1026,9 @@ struct parameter
     /* An int parameter.  */
     INT,
 
+    /* An unsigned int parameter.  */
+    UINT,
+
     /* A HOST_WIDE_INT parameter.  */
     WIDE_INT
   };
@@ -1009,8 +1071,9 @@ operator != (const parameter &param1, const parameter &param2)
    an ad-hoc enum value on success and -1 on failure.  The routine can
    be used by any subroutine type.  The match can be parameterized by
    things like mode, code and UNSPEC number.  */
-struct pattern_routine
+class pattern_routine
 {
+public:
   /* The state that implements the pattern.  */
   state *s;
 
@@ -1036,8 +1099,9 @@ struct pattern_routine
 static vec <pattern_routine *> patterns;
 
 /* Represents one use of a pattern routine.  */
-struct pattern_use
+class pattern_use
 {
+public:
   /* The pattern routine to use.  */
   pattern_routine *routine;
 
@@ -1047,9 +1111,10 @@ struct pattern_use
 };
 
 /* Represents a test performed by a decision.  */
-struct test
+class rtx_test
 {
-  test ();
+public:
+  rtx_test ();
 
   /* The types of test that can be performed.  Most of them take as input
      an rtx X.  Some also take as input a transition label LABEL; the others
@@ -1063,6 +1128,12 @@ struct test
     /* Check GET_MODE (X) == LABEL.  */
     MODE,
 
+    /* Check REGNO (X) == LABEL.  */
+    REGNO_FIELD,
+
+    /* Check known_eq (SUBREG_BYTE (X), LABEL).  */
+    SUBREG_FIELD,
+
     /* Check XINT (X, u.opno) == LABEL.  */
     INT_FIELD,
 
@@ -1140,136 +1211,152 @@ struct test
     acceptance_type acceptance;
   } u;
 
-  static test code (position *);
-  static test mode (position *);
-  static test int_field (position *, int);
-  static test wide_int_field (position *, int);
-  static test veclen (position *);
-  static test peep2_count (int);
-  static test veclen_ge (position *, int);
-  static test predicate (position *, const pred_data *, machine_mode);
-  static test duplicate (position *, int);
-  static test pattern (position *, pattern_use *);
-  static test have_num_clobbers ();
-  static test c_test (const char *);
-  static test set_op (position *, int);
-  static test accept (const acceptance_type &);
+  static rtx_test code (position *);
+  static rtx_test mode (position *);
+  static rtx_test regno_field (position *);
+  static rtx_test subreg_field (position *);
+  static rtx_test int_field (position *, int);
+  static rtx_test wide_int_field (position *, int);
+  static rtx_test veclen (position *);
+  static rtx_test peep2_count (int);
+  static rtx_test veclen_ge (position *, int);
+  static rtx_test predicate (position *, const pred_data *, machine_mode);
+  static rtx_test duplicate (position *, int);
+  static rtx_test pattern (position *, pattern_use *);
+  static rtx_test have_num_clobbers ();
+  static rtx_test c_test (const char *);
+  static rtx_test set_op (position *, int);
+  static rtx_test accept (const acceptance_type &);
 
   bool terminal_p () const;
   bool single_outcome_p () const;
 
 private:
-  test (position *, kind_enum);
+  rtx_test (position *, kind_enum);
 };
 
-test::test () {}
+rtx_test::rtx_test () {}
 
-test::test (position *pos_in, kind_enum kind_in)
+rtx_test::rtx_test (position *pos_in, kind_enum kind_in)
   : pos (pos_in), pos_operand (-1), kind (kind_in) {}
 
-test
-test::code (position *pos)
+rtx_test
+rtx_test::code (position *pos)
+{
+  return rtx_test (pos, rtx_test::CODE);
+}
+
+rtx_test
+rtx_test::mode (position *pos)
 {
-  return test (pos, test::CODE);
+  return rtx_test (pos, rtx_test::MODE);
 }
 
-test
-test::mode (position *pos)
+rtx_test
+rtx_test::regno_field (position *pos)
 {
-  return test (pos, test::MODE);
+  rtx_test res (pos, rtx_test::REGNO_FIELD);
+  return res;
 }
 
-test
-test::int_field (position *pos, int opno)
+rtx_test
+rtx_test::subreg_field (position *pos)
 {
-  test res (pos, test::INT_FIELD);
+  rtx_test res (pos, rtx_test::SUBREG_FIELD);
+  return res;
+}
+
+rtx_test
+rtx_test::int_field (position *pos, int opno)
+{
+  rtx_test res (pos, rtx_test::INT_FIELD);
   res.u.opno = opno;
   return res;
 }
 
-test
-test::wide_int_field (position *pos, int opno)
+rtx_test
+rtx_test::wide_int_field (position *pos, int opno)
 {
-  test res (pos, test::WIDE_INT_FIELD);
+  rtx_test res (pos, rtx_test::WIDE_INT_FIELD);
   res.u.opno = opno;
   return res;
 }
 
-test
-test::veclen (position *pos)
+rtx_test
+rtx_test::veclen (position *pos)
 {
-  return test (pos, test::VECLEN);
+  return rtx_test (pos, rtx_test::VECLEN);
 }
 
-test
-test::peep2_count (int min_len)
+rtx_test
+rtx_test::peep2_count (int min_len)
 {
-  test res (0, test::PEEP2_COUNT);
+  rtx_test res (0, rtx_test::PEEP2_COUNT);
   res.u.min_len = min_len;
   return res;
 }
 
-test
-test::veclen_ge (position *pos, int min_len)
+rtx_test
+rtx_test::veclen_ge (position *pos, int min_len)
 {
-  test res (pos, test::VECLEN_GE);
+  rtx_test res (pos, rtx_test::VECLEN_GE);
   res.u.min_len = min_len;
   return res;
 }
 
-test
-test::predicate (position *pos, const struct pred_data *data,
-                machine_mode mode)
+rtx_test
+rtx_test::predicate (position *pos, const struct pred_data *data,
+                    machine_mode mode)
 {
-  test res (pos, test::PREDICATE);
+  rtx_test res (pos, rtx_test::PREDICATE);
   res.u.predicate.data = data;
   res.u.predicate.mode_is_param = false;
   res.u.predicate.mode = mode;
   return res;
 }
 
-test
-test::duplicate (position *pos, int opno)
+rtx_test
+rtx_test::duplicate (position *pos, int opno)
 {
-  test res (pos, test::DUPLICATE);
+  rtx_test res (pos, rtx_test::DUPLICATE);
   res.u.opno = opno;
   return res;
 }
 
-test
-test::pattern (position *pos, pattern_use *pattern)
+rtx_test
+rtx_test::pattern (position *pos, pattern_use *pattern)
 {
-  test res (pos, test::PATTERN);
+  rtx_test res (pos, rtx_test::PATTERN);
   res.u.pattern = pattern;
   return res;
 }
 
-test
-test::have_num_clobbers ()
+rtx_test
+rtx_test::have_num_clobbers ()
 {
-  return test (0, test::HAVE_NUM_CLOBBERS);
+  return rtx_test (0, rtx_test::HAVE_NUM_CLOBBERS);
 }
 
-test
-test::c_test (const char *string)
+rtx_test
+rtx_test::c_test (const char *string)
 {
-  test res (0, test::C_TEST);
+  rtx_test res (0, rtx_test::C_TEST);
   res.u.string = string;
   return res;
 }
 
-test
-test::set_op (position *pos, int opno)
+rtx_test
+rtx_test::set_op (position *pos, int opno)
 {
-  test res (pos, test::SET_OP);
+  rtx_test res (pos, rtx_test::SET_OP);
   res.u.opno = opno;
   return res;
 }
 
-test
-test::accept (const acceptance_type &acceptance)
+rtx_test
+rtx_test::accept (const acceptance_type &acceptance)
 {
-  test res (0, test::ACCEPT);
+  rtx_test res (0, rtx_test::ACCEPT);
   res.u.acceptance = acceptance;
   return res;
 }
@@ -1277,74 +1364,77 @@ test::accept (const acceptance_type &acceptance)
 /* Return true if the test represents an unconditionally successful match.  */
 
 bool
-test::terminal_p () const
+rtx_test::terminal_p () const
 {
-  return kind == test::ACCEPT && u.acceptance.type != PEEPHOLE2;
+  return kind == rtx_test::ACCEPT && u.acceptance.type != PEEPHOLE2;
 }
 
 /* Return true if the test is a boolean that is always true.  */
 
 bool
-test::single_outcome_p () const
+rtx_test::single_outcome_p () const
 {
-  return terminal_p () || kind == test::SET_OP;
+  return terminal_p () || kind == rtx_test::SET_OP;
 }
 
 bool
-operator == (const test &a, const test &b)
+operator == (const rtx_test &a, const rtx_test &b)
 {
   if (a.pos != b.pos || a.kind != b.kind)
     return false;
   switch (a.kind)
     {
-    case test::CODE:
-    case test::MODE:
-    case test::VECLEN:
-    case test::HAVE_NUM_CLOBBERS:
+    case rtx_test::CODE:
+    case rtx_test::MODE:
+    case rtx_test::REGNO_FIELD:
+    case rtx_test::SUBREG_FIELD:
+    case rtx_test::VECLEN:
+    case rtx_test::HAVE_NUM_CLOBBERS:
       return true;
 
-    case test::PEEP2_COUNT:
-    case test::VECLEN_GE:
+    case rtx_test::PEEP2_COUNT:
+    case rtx_test::VECLEN_GE:
       return a.u.min_len == b.u.min_len;
 
-    case test::INT_FIELD:
-    case test::WIDE_INT_FIELD:
-    case test::DUPLICATE:
-    case test::SET_OP:
+    case rtx_test::INT_FIELD:
+    case rtx_test::WIDE_INT_FIELD:
+    case rtx_test::DUPLICATE:
+    case rtx_test::SET_OP:
       return a.u.opno == b.u.opno;
 
-    case test::SAVED_CONST_INT:
+    case rtx_test::SAVED_CONST_INT:
       return (a.u.integer.is_param == b.u.integer.is_param
              && a.u.integer.value == b.u.integer.value);
 
-    case test::PREDICATE:
+    case rtx_test::PREDICATE:
       return (a.u.predicate.data == b.u.predicate.data
              && a.u.predicate.mode_is_param == b.u.predicate.mode_is_param
              && a.u.predicate.mode == b.u.predicate.mode);
 
-    case test::PATTERN:
+    case rtx_test::PATTERN:
       return (a.u.pattern->routine == b.u.pattern->routine
              && a.u.pattern->params == b.u.pattern->params);
 
-    case test::C_TEST:
+    case rtx_test::C_TEST:
       return strcmp (a.u.string, b.u.string) == 0;
 
-    case test::ACCEPT:
+    case rtx_test::ACCEPT:
       return a.u.acceptance == b.u.acceptance;
     }
   gcc_unreachable ();
 }
 
 bool
-operator != (const test &a, const test &b)
+operator != (const rtx_test &a, const rtx_test &b)
 {
   return !operator == (a, b);
 }
 
 /* A simple set of transition labels.  Most transitions have a singleton
    label, so try to make that case as efficient as possible.  */
-struct int_set : public auto_vec <uint64_t, 1>
+class int_set : public auto_vec <uint64_t, 1>
 {
+public:
   typedef uint64_t *iterator;
 
   int_set ();
@@ -1357,14 +1447,16 @@ struct int_set : public auto_vec <uint64_t, 1>
   iterator end ();
 };
 
-int_set::int_set () {}
+int_set::int_set () : auto_vec<uint64_t, 1> () {}
 
-int_set::int_set (uint64_t label)
+int_set::int_set (uint64_t label) :
+  auto_vec<uint64_t, 1> ()
 {
   safe_push (label);
 }
 
-int_set::int_set (const int_set &other)
+int_set::int_set (const int_set &other) :
+  auto_vec<uint64_t, 1> ()
 {
   safe_splice (other);
 }
@@ -1406,12 +1498,13 @@ operator != (const int_set &a, const int_set &b)
   return !operator == (a, b);
 }
 
-struct decision;
+class decision;
 
 /* Represents a transition between states, dependent on the result of
    a test T.  */
-struct transition
+class transition
 {
+public:
   transition (const int_set &, state *, bool);
 
   void set_parent (list_head <transition> *);
@@ -1420,8 +1513,8 @@ struct transition
   transition *prev, *next;
 
   /* The transition should be taken when T has one of these values.
-     E.g. for test::CODE this is a set of codes, while for booleans like
-     test::PREDICATE it is always a singleton "true".  The labels are
+     E.g. for rtx_test::CODE this is a set of codes, while for booleans like
+     rtx_test::PREDICATE it is always a singleton "true".  The labels are
      sorted in ascending order.  */
   int_set labels;
 
@@ -1439,7 +1532,7 @@ struct transition
   bool optional;
 
   /* True if LABELS contains parameter numbers rather than constants.
-     E.g. if this is true for a test::CODE, the label is the number
+     E.g. if this is true for a rtx_test::CODE, the label is the number
      of an rtx_code parameter rather than an rtx_code itself.
      LABELS is always a singleton when this variable is true.  */
   bool is_param;
@@ -1450,9 +1543,10 @@ struct transition
    to the transition's target state.  If no suitable transition exists,
    the machine either falls through to the next decision or, if there are no
    more decisions to try, fails the match.  */
-struct decision : list_head <transition>
+class decision : public list_head <transition>
 {
-  decision (const test &);
+public:
+  decision (const rtx_test &);
 
   void set_parent (list_head <decision> *s);
   bool if_statement_p (uint64_t * = 0) const;
@@ -1464,14 +1558,15 @@ struct decision : list_head <transition>
   decision *prev, *next;
 
   /* The test to perform.  */
-  struct test test;
+  rtx_test test;
 };
 
 /* Represents one machine state.  For each state the machine tries a list
    of decisions, in order, and acts on the first match.  It fails without
    further backtracking if no decisions match.  */
-struct state : list_head <decision>
+class state : public list_head <decision>
 {
+public:
   void set_parent (list_head <state> *) {}
 };
 
@@ -1488,7 +1583,7 @@ transition::set_parent (list_head <transition> *from_in)
   from = static_cast <decision *> (from_in);
 }
 
-decision::decision (const struct test &test_in)
+decision::decision (const rtx_test &test_in)
   : prev (0), next (0), test (test_in) {}
 
 /* Set the state to which this decision belongs.  */
@@ -1518,7 +1613,7 @@ decision::if_statement_p (uint64_t *label) const
    TRANS.  */
 
 static void
-add_decision (state *from, const test &test, transition *trans)
+add_decision (state *from, const rtx_test &test, transition *trans)
 {
   decision *d = new decision (test);
   from->push_back (d);
@@ -1530,7 +1625,7 @@ add_decision (state *from, const test &test, transition *trans)
    should be optional.  Return the new state.  */
 
 static state *
-add_decision (state *from, const test &test, int_set labels, bool optional)
+add_decision (state *from, const rtx_test &test, int_set labels, bool optional)
 {
   state *to = new state;
   add_decision (from, test, new transition (labels, to, optional));
@@ -1542,7 +1637,7 @@ add_decision (state *from, const test &test, int_set labels, bool optional)
    optional.  */
 
 static decision *
-insert_decision_before (state::range r, const test &test,
+insert_decision_before (state::range r, const rtx_test &test,
                        const int_set &labels, bool optional)
 {
   decision *newd = new decision (test);
@@ -1593,17 +1688,18 @@ simplify_tests (state *s)
       uint64_t label;
       /* Convert checks for GET_CODE (x) == CONST_INT and XWINT (x, 0) == N
         into checks for const_int_rtx[N'], if N is suitably small.  */
-      if (d->test.kind == test::CODE
+      if (d->test.kind == rtx_test::CODE
          && d->if_statement_p (&label)
          && label == CONST_INT)
        if (decision *second = d->first->to->singleton ())
-         if (second->test.kind == test::WIDE_INT_FIELD
+         if (d->test.pos == second->test.pos
+             && second->test.kind == rtx_test::WIDE_INT_FIELD
              && second->test.u.opno == 0
              && second->if_statement_p (&label)
              && IN_RANGE (int64_t (label),
                           -MAX_SAVED_CONST_INT, MAX_SAVED_CONST_INT))
            {
-             d->test.kind = test::SAVED_CONST_INT;
+             d->test.kind = rtx_test::SAVED_CONST_INT;
              d->test.u.integer.is_param = false;
              d->test.u.integer.value = label;
              d->replace (d->first, second->release ());
@@ -1618,7 +1714,7 @@ simplify_tests (state *s)
         paths that reach that code test require the same predicate
         to be true.  cse_tests will then put the predicate test in
         series with the code test.  */
-      if (d->test.kind == test::CODE)
+      if (d->test.kind == rtx_test::CODE)
        if (transition *trans = d->singleton ())
          {
            state *s = trans->to;
@@ -1629,7 +1725,7 @@ simplify_tests (state *s)
                transition *trans2 = d2->singleton ();
                if (!trans2)
                  break;
-               if (d2->test.kind == test::PREDICATE)
+               if (d2->test.kind == rtx_test::PREDICATE)
                  {
                    d->test = d2->test;
                    trans->labels = int_set (true);
@@ -1653,7 +1749,7 @@ simplify_tests (state *s)
 static bool
 common_test_p (decision *d, transition *common, vec <transition *> *where)
 {
-  if (d->test.kind == test::ACCEPT)
+  if (d->test.kind == rtx_test::ACCEPT)
     /* We found a successful return that didn't require COMMON.  */
     return false;
   if (d->test == common->from->test)
@@ -1680,8 +1776,9 @@ const unsigned char TESTED_CODE = 1;
 const unsigned char TESTED_VECLEN = 2;
 
 /* Represents a set of conditions that are known to hold.  */
-struct known_conditions
+class known_conditions
 {
+public:
   /* A mask of TESTED_ values for each position, indexed by the position's
      id field.  */
   auto_vec <unsigned char> position_tests;
@@ -1701,20 +1798,20 @@ struct known_conditions
    as positive proof.  */
 
 static bool
-safe_to_hoist_p (decision *d, const test &test, known_conditions *kc)
+safe_to_hoist_p (decision *d, const rtx_test &test, known_conditions *kc)
 {
   switch (test.kind)
     {
-    case test::C_TEST:
+    case rtx_test::C_TEST:
       /* In general, C tests require everything else to have been
         verified and all operands to have been set up.  */
       return false;
 
-    case test::ACCEPT:
+    case rtx_test::ACCEPT:
       /* Don't accept something before all conditions have been tested.  */
       return false;
 
-    case test::PREDICATE:
+    case rtx_test::PREDICATE:
       /* Don't move a predicate over a test for VECLEN_GE, since the
         predicate used in a match_parallel can legitimately expect the
         length to be checked first.  */
@@ -1722,21 +1819,21 @@ safe_to_hoist_p (decision *d, const test &test, known_conditions *kc)
           subd->test != test;
           subd = subd->first->to->first)
        if (subd->test.pos == test.pos
-           && subd->test.kind == test::VECLEN_GE)
+           && subd->test.kind == rtx_test::VECLEN_GE)
          return false;
       goto any_rtx;
 
-    case test::DUPLICATE:
+    case rtx_test::DUPLICATE:
       /* Don't test for a match_dup until the associated operand has
         been set.  */
       if (!kc->set_operands[test.u.opno])
        return false;
       goto any_rtx;
 
-    case test::CODE:
-    case test::MODE:
-    case test::SAVED_CONST_INT:
-    case test::SET_OP:
+    case rtx_test::CODE:
+    case rtx_test::MODE:
+    case rtx_test::SAVED_CONST_INT:
+    case rtx_test::SET_OP:
     any_rtx:
       /* Check whether it is safe to access the rtx under test.  */
       switch (test.pos->type)
@@ -1752,20 +1849,22 @@ safe_to_hoist_p (decision *d, const test &test, known_conditions *kc)
        }
       gcc_unreachable ();
 
-    case test::INT_FIELD:
-    case test::WIDE_INT_FIELD:
-    case test::VECLEN:
-    case test::VECLEN_GE:
+    case rtx_test::REGNO_FIELD:
+    case rtx_test::SUBREG_FIELD:
+    case rtx_test::INT_FIELD:
+    case rtx_test::WIDE_INT_FIELD:
+    case rtx_test::VECLEN:
+    case rtx_test::VECLEN_GE:
       /* These tests access a specific part of an rtx, so are only safe
         once we know what the rtx is.  */
       return kc->position_tests[test.pos->id] & TESTED_CODE;
 
-    case test::PEEP2_COUNT:
-    case test::HAVE_NUM_CLOBBERS:
+    case rtx_test::PEEP2_COUNT:
+    case rtx_test::HAVE_NUM_CLOBBERS:
       /* These tests can be performed anywhere.  */
       return true;
 
-    case test::PATTERN:
+    case rtx_test::PATTERN:
       gcc_unreachable ();
     }
   gcc_unreachable ();
@@ -1886,8 +1985,8 @@ cse_tests (position *pos, state *s, known_conditions *kc)
       /* Make sure that safe_to_hoist_p isn't being overly conservative.
         It should realize that D's test is safe in the current
         environment.  */
-      gcc_assert (d->test.kind == test::C_TEST
-                 || d->test.kind == test::ACCEPT
+      gcc_assert (d->test.kind == rtx_test::C_TEST
+                 || d->test.kind == rtx_test::ACCEPT
                  || safe_to_hoist_p (d, d->test, kc));
 
       /* D won't be changed any further by the current optimization.
@@ -1895,24 +1994,24 @@ cse_tests (position *pos, state *s, known_conditions *kc)
       int prev = 0;
       switch (d->test.kind)
        {
-       case test::CODE:
+       case rtx_test::CODE:
          prev = kc->position_tests[d->test.pos->id];
          kc->position_tests[d->test.pos->id] |= TESTED_CODE;
          break;
 
-       case test::VECLEN:
-       case test::VECLEN_GE:
+       case rtx_test::VECLEN:
+       case rtx_test::VECLEN_GE:
          prev = kc->position_tests[d->test.pos->id];
          kc->position_tests[d->test.pos->id] |= TESTED_VECLEN;
          break;
 
-       case test::SET_OP:
+       case rtx_test::SET_OP:
          prev = kc->set_operands[d->test.u.opno];
          gcc_assert (!prev);
          kc->set_operands[d->test.u.opno] = true;
          break;
 
-       case test::PEEP2_COUNT:
+       case rtx_test::PEEP2_COUNT:
          prev = kc->peep2_count;
          kc->peep2_count = MAX (prev, d->test.u.min_len);
          break;
@@ -1924,17 +2023,17 @@ cse_tests (position *pos, state *s, known_conditions *kc)
        cse_tests (d->test.pos ? d->test.pos : pos, trans->to, kc);
       switch (d->test.kind)
        {
-       case test::CODE:
-       case test::VECLEN:
-       case test::VECLEN_GE:
+       case rtx_test::CODE:
+       case rtx_test::VECLEN:
+       case rtx_test::VECLEN_GE:
          kc->position_tests[d->test.pos->id] = prev;
          break;
 
-       case test::SET_OP:
+       case rtx_test::SET_OP:
          kc->set_operands[d->test.u.opno] = prev;
          break;
 
-       case test::PEEP2_COUNT:
+       case rtx_test::PEEP2_COUNT:
          kc->peep2_count = prev;
          break;
 
@@ -1948,33 +2047,37 @@ cse_tests (position *pos, state *s, known_conditions *kc)
    or parameter::UNSET if none.  */
 
 parameter::type_enum
-transition_parameter_type (test::kind_enum kind)
+transition_parameter_type (rtx_test::kind_enum kind)
 {
   switch (kind)
     {
-    case test::CODE:
+    case rtx_test::CODE:
       return parameter::CODE;
 
-    case test::MODE:
+    case rtx_test::MODE:
       return parameter::MODE;
 
-    case test::INT_FIELD:
-    case test::VECLEN:
-    case test::PATTERN:
+    case rtx_test::REGNO_FIELD:
+    case rtx_test::SUBREG_FIELD:
+      return parameter::UINT;
+
+    case rtx_test::INT_FIELD:
+    case rtx_test::VECLEN:
+    case rtx_test::PATTERN:
       return parameter::INT;
 
-    case test::WIDE_INT_FIELD:
+    case rtx_test::WIDE_INT_FIELD:
       return parameter::WIDE_INT;
 
-    case test::PEEP2_COUNT:
-    case test::VECLEN_GE:
-    case test::SAVED_CONST_INT:
-    case test::PREDICATE:
-    case test::DUPLICATE:
-    case test::HAVE_NUM_CLOBBERS:
-    case test::C_TEST:
-    case test::SET_OP:
-    case test::ACCEPT:
+    case rtx_test::PEEP2_COUNT:
+    case rtx_test::VECLEN_GE:
+    case rtx_test::SAVED_CONST_INT:
+    case rtx_test::PREDICATE:
+    case rtx_test::DUPLICATE:
+    case rtx_test::HAVE_NUM_CLOBBERS:
+    case rtx_test::C_TEST:
+    case rtx_test::SET_OP:
+    case rtx_test::ACCEPT:
       return parameter::UNSET;
     }
   gcc_unreachable ();
@@ -1992,18 +2095,19 @@ find_operand_positions (state *s, vec <int> &operand_pos)
       int this_operand = (d->test.pos ? operand_pos[d->test.pos->id] : -1);
       if (this_operand >= 0)
        d->test.pos_operand = this_operand;
-      if (d->test.kind == test::SET_OP)
+      if (d->test.kind == rtx_test::SET_OP)
        operand_pos[d->test.pos->id] = d->test.u.opno;
       for (transition *trans = d->first; trans; trans = trans->next)
        find_operand_positions (trans->to, operand_pos);
-      if (d->test.kind == test::SET_OP)
+      if (d->test.kind == rtx_test::SET_OP)
        operand_pos[d->test.pos->id] = this_operand;
     }
 }
 
 /* Statistics about a matching routine.  */
-struct stats
+class stats
 {
+public:
   stats ();
 
   /* The total number of decisions in the routine, excluding trivial
@@ -2064,7 +2168,7 @@ get_stats (state *s)
          for_d.num_decisions += 1;
          for_d.longest_path += 1;
        }
-      if (d->test.kind == test::ACCEPT)
+      if (d->test.kind == rtx_test::ACCEPT)
        {
          for_d.longest_path_code = d->test.u.acceptance.u.full.code;
          for_d.longest_backtrack_code = d->test.u.acceptance.u.full.code;
@@ -2139,11 +2243,12 @@ optimize_subroutine_group (const char *type, state *root)
           st.longest_backtrack, st.longest_backtrack_code);
 }
 
-struct merge_pattern_info;
+class merge_pattern_info;
 
 /* Represents a transition from one pattern to another.  */
-struct merge_pattern_transition
+class merge_pattern_transition
 {
+public:
   merge_pattern_transition (merge_pattern_info *);
 
   /* The target pattern.  */
@@ -2163,8 +2268,9 @@ merge_pattern_transition::merge_pattern_transition (merge_pattern_info *to_in)
 /* Represents a pattern that can might match several states.  The pattern
    may replace parts of the test with a parameter value.  It may also
    replace transition labels with parameters.  */
-struct merge_pattern_info
+class merge_pattern_info
 {
+public:
   merge_pattern_info (unsigned int);
 
   /* If PARAM_TEST_P, the state's singleton test should be generalized
@@ -2236,8 +2342,9 @@ merge_pattern_info::merge_pattern_info (unsigned int num_transitions)
 
 /* Describes one way of matching a particular state to a particular
    pattern.  */
-struct merge_state_result
+class merge_state_result
 {
+public:
   merge_state_result (merge_pattern_info *, position *, merge_state_result *);
 
   /* A pattern that matches the state.  */
@@ -2267,8 +2374,9 @@ merge_state_result::merge_state_result (merge_pattern_info *pattern_in,
 
 /* Information about a state, used while trying to match it against
    a pattern.  */
-struct merge_state_info
+class merge_state_info
 {
+public:
   merge_state_info (state *);
 
   /* The state itself.  */
@@ -2378,21 +2486,21 @@ update_parameters (vec <parameter> &to, const vec <parameter> &from)
    PARAMB alone.  */
 
 static bool
-compatible_tests_p (const test &a, const test &b,
+compatible_tests_p (const rtx_test &a, const rtx_test &b,
                    parameter *parama, parameter *paramb)
 {
   if (a.kind != b.kind)
     return false;
   switch (a.kind)
     {
-    case test::PREDICATE:
+    case rtx_test::PREDICATE:
       if (a.u.predicate.data != b.u.predicate.data)
        return false;
       *parama = parameter (parameter::MODE, false, a.u.predicate.mode);
       *paramb = parameter (parameter::MODE, false, b.u.predicate.mode);
       return true;
 
-    case test::SAVED_CONST_INT:
+    case rtx_test::SAVED_CONST_INT:
       *parama = parameter (parameter::INT, false, a.u.integer.value);
       *paramb = parameter (parameter::INT, false, b.u.integer.value);
       return true;
@@ -2501,10 +2609,8 @@ merge_relative_positions (position **roota, position *a,
 
 /* A hasher of states that treats two states as "equal" if they might be
    merged (but trying to be more discriminating than "return true").  */
-struct test_pattern_hasher : typed_noop_remove <merge_state_info>
+struct test_pattern_hasher : nofree_ptr_hash <merge_state_info>
 {
-  typedef merge_state_info *value_type;
-  typedef merge_state_info *compare_type;
   static inline hashval_t hash (const value_type &);
   static inline bool equal (const value_type &, const compare_type &);
 };
@@ -2666,7 +2772,7 @@ merge_patterns (merge_state_info *sinfo1, merge_state_info *sinfo2)
             parameterizing the first N const_ints of the vector
             and then (once we reach the maximum number of parameters)
             we go on to match the other elements exactly.  */
-         if (d1->test.kind == test::WIDE_INT_FIELD)
+         if (d1->test.kind == rtx_test::WIDE_INT_FIELD)
            return false;
 
          /* See whether the label has a generalizable type.  */
@@ -2802,7 +2908,7 @@ init_pattern_use (create_pattern_info *cpi, merge_state_info *sinfo,
   pattern_use *use = new pattern_use;
   use->routine = pat->routine;
   use->params.splice (params);
-  decision *d = new decision (test::pattern (res->root, use));
+  decision *d = new decision (rtx_test::pattern (res->root, use));
 
   /* If the original decision could use an element of operands[] instead
      of an rtx variable, try to transfer it to the new decision.  */
@@ -2822,7 +2928,7 @@ add_pattern_acceptance (create_pattern_info *cpi, state *s)
   acceptance.type = SUBPATTERN;
   acceptance.partial_p = false;
   acceptance.u.full.code = cpi->next_result;
-  add_decision (s, test::accept (acceptance), true, false);
+  add_decision (s, rtx_test::accept (acceptance), true, false);
   cpi->next_result += 1;
 }
 
@@ -2859,12 +2965,12 @@ populate_pattern_routine (create_pattern_info *cpi, merge_state_info *sinfo,
       const parameter &param = params[pat->param_test];
       switch (newd->test.kind)
        {
-       case test::PREDICATE:
+       case rtx_test::PREDICATE:
          newd->test.u.predicate.mode_is_param = param.is_param;
          newd->test.u.predicate.mode = param.value;
          break;
 
-       case test::SAVED_CONST_INT:
+       case rtx_test::SAVED_CONST_INT:
          newd->test.u.integer.is_param = param.is_param;
          newd->test.u.integer.value = param.value;
          break;
@@ -2874,9 +2980,9 @@ populate_pattern_routine (create_pattern_info *cpi, merge_state_info *sinfo,
          break;
        }
     }
-  if (d->test.kind == test::C_TEST)
+  if (d->test.kind == rtx_test::C_TEST)
     routine->insn_p = true;
-  else if (d->test.kind == test::HAVE_NUM_CLOBBERS)
+  else if (d->test.kind == rtx_test::HAVE_NUM_CLOBBERS)
     routine->pnum_clobbers_p = true;
   news->push_back (newd);
 
@@ -3037,11 +3143,11 @@ split_out_patterns (vec <merge_state_info> &states)
         and so couldn't be shared between states).  */
       if (decision *d = sinfo->s->singleton ())
        /* ACCEPT states are unique, so don't even try to merge them.  */
-       if (d->test.kind != test::ACCEPT
+       if (d->test.kind != rtx_test::ACCEPT
            && (pattern_have_num_clobbers_p
-               || d->test.kind != test::HAVE_NUM_CLOBBERS)
+               || d->test.kind != rtx_test::HAVE_NUM_CLOBBERS)
            && (pattern_c_test_p
-               || d->test.kind != test::C_TEST))
+               || d->test.kind != rtx_test::C_TEST))
          {
            merge_state_info **slot = hashtab.find_slot (sinfo, INSERT);
            sinfo->prev_same_test = *slot;
@@ -3289,7 +3395,7 @@ create_subroutine (routine_type type, state *s, vec <state *> &procs)
   acceptance.partial_p = true;
   acceptance.u.subroutine_id = procs.length ();
   state *news = new state;
-  add_decision (news, test::accept (acceptance), true, false);
+  add_decision (news, rtx_test::accept (acceptance), true, false);
   return news;
 }
 
@@ -3326,8 +3432,8 @@ find_subroutines (routine_type type, state *s, vec <state *> &procs)
                if (!newd->test.single_outcome_p ())
                  size.num_statements += 1;
                trans = newd->singleton ();
-               if (newd->test.kind == test::SET_OP
-                   || newd->test.kind == test::ACCEPT)
+               if (newd->test.kind == rtx_test::SET_OP
+                   || newd->test.kind == rtx_test::ACCEPT)
                  break;
              }
          /* The target of TRANS is a subroutine candidate.  First recurse
@@ -3386,7 +3492,8 @@ safe_predicate_mode (const struct pred_data *pred, machine_mode mode)
   if (GET_MODE_CLASS (mode) == MODE_INT
       && (pred->codes[CONST_INT]
          || pred->codes[CONST_DOUBLE]
-         || pred->codes[CONST_WIDE_INT]))
+         || pred->codes[CONST_WIDE_INT]
+         || pred->codes[LABEL_REF]))
     return false;
 
   return !pred->special && mode != VOIDmode;
@@ -3768,7 +3875,8 @@ merge_into_state (state *s1, state *s2)
 
 /* Pairs a pattern that needs to be matched with the rtx position at
    which the pattern should occur.  */
-struct pattern_pos {
+class pattern_pos {
+public:
   pattern_pos () {}
   pattern_pos (rtx, position *);
 
@@ -3791,23 +3899,12 @@ operator < (const pattern_pos &e1, const pattern_pos &e2)
   return diff < 0;
 }
 
-/* Return the name of the predicate matched by MATCH_RTX.  */
-
-static const char *
-predicate_name (rtx match_rtx)
-{
-  if (GET_CODE (match_rtx) == MATCH_SCRATCH)
-    return "scratch_operand";
-  else
-    return XSTR (match_rtx, 1);
-}
-
 /* Add new decisions to S that check whether the rtx at position POS
    matches PATTERN.  Return the state that is reached in that case.
    TOP_PATTERN is the overall pattern, as passed to match_pattern_1.  */
 
 static state *
-match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
+match_pattern_2 (state *s, md_rtx_info *info, position *pos, rtx pattern)
 {
   auto_vec <pattern_pos, 32> worklist;
   auto_vec <pattern_pos, 32> pred_and_mode_tests;
@@ -3832,7 +3929,7 @@ match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
          dup_tests.safe_push (pattern_pos (pattern, pos));
 
          /* Use the same code check as the original operand.  */
-         pattern = find_operand (top_pattern, XINT (pattern, 0), NULL_RTX);
+         pattern = find_operand (info->def, XINT (pattern, 0), NULL_RTX);
          /* Fall through.  */
 
        case MATCH_PARALLEL:
@@ -3849,25 +3946,22 @@ match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
                if (code == GET_CODE (pattern))
                  {
                    if (!pred)
-                     error_with_line (pattern_lineno,
-                                      "unknown predicate '%s'"
-                                      " in '%s' expression",
-                                      pred_name, GET_RTX_NAME (code));
+                     error_at (info->loc, "unknown predicate '%s' used in %s",
+                               pred_name, GET_RTX_NAME (code));
                    else if (code == MATCH_PARALLEL
                             && pred->singleton != PARALLEL)
-                     error_with_line (pattern_lineno,
-                                      "predicate '%s' used in match_parallel"
-                                      " does not allow only PARALLEL",
-                                      pred->name);
+                     error_at (info->loc, "predicate '%s' used in"
+                               " match_parallel does not allow only PARALLEL",
+                               pred->name);
                  }
              }
 
            if (code == MATCH_PARALLEL || code == MATCH_PAR_DUP)
              {
                /* Check that we have a parallel with enough elements.  */
-               s = add_decision (s, test::code (pos), PARALLEL, false);
+               s = add_decision (s, rtx_test::code (pos), PARALLEL, false);
                int min_len = XVECLEN (pattern, 2);
-               s = add_decision (s, test::veclen_ge (pos, min_len),
+               s = add_decision (s, rtx_test::veclen_ge (pos, min_len),
                                  true, false);
              }
            else
@@ -3882,7 +3976,7 @@ match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
                bool need_codes = (pred
                                   && (code == MATCH_OPERATOR
                                       || code == MATCH_OP_DUP));
-               s = add_decision (s, test::code (pos), codes, !need_codes);
+               s = add_decision (s, rtx_test::code (pos), codes, !need_codes);
              }
 
            /* Postpone the predicate check until we've checked the rest
@@ -3923,7 +4017,7 @@ match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
        default:
          {
            /* Check that the rtx has the right code.  */
-           s = add_decision (s, test::code (pos), code, false);
+           s = add_decision (s, rtx_test::code (pos), code, false);
 
            /* Queue a test for the mode if one is specified.  */
            if (GET_MODE (pattern) != VOIDmode)
@@ -3948,7 +4042,8 @@ match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
                      /* Make sure the vector has the right number of
                         elements.  */
                      int length = XVECLEN (pattern, i);
-                     s = add_decision (s, test::veclen (pos), length, false);
+                     s = add_decision (s, rtx_test::veclen (pos),
+                                       length, false);
 
                      position **subpos2_ptr = &pos->xvecexp0s;
                      for (int j = 0; j < length; j++)
@@ -3964,16 +4059,31 @@ match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
 
                  case 'i':
                    /* Make sure that XINT (X, I) has the right value.  */
-                   s = add_decision (s, test::int_field (pos, i),
+                   s = add_decision (s, rtx_test::int_field (pos, i),
                                      XINT (pattern, i), false);
                    break;
 
+                 case 'r':
+                   /* Make sure that REGNO (X) has the right value.  */
+                   gcc_assert (i == 0);
+                   s = add_decision (s, rtx_test::regno_field (pos),
+                                     REGNO (pattern), false);
+                   break;
+
                  case 'w':
                    /* Make sure that XWINT (X, I) has the right value.  */
-                   s = add_decision (s, test::wide_int_field (pos, i),
+                   s = add_decision (s, rtx_test::wide_int_field (pos, i),
                                      XWINT (pattern, 0), false);
                    break;
 
+                 case 'p':
+                   /* We don't have a way of parsing polynomial offsets yet,
+                      and hopefully never will.  */
+                   s = add_decision (s, rtx_test::subreg_field (pos),
+                                     SUBREG_BYTE (pattern).to_constant (),
+                                     false);
+                   break;
+
                  case '0':
                    break;
 
@@ -4035,8 +4145,8 @@ match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
                /* Check the mode first, to distinguish things like SImode
                   and DImode register_operands, as described above.  */
                machine_mode mode = GET_MODE (e->pattern);
-               if (safe_predicate_mode (pred, mode))
-                 s = add_decision (s, test::mode (e->pos), mode, true);
+               if (pred && safe_predicate_mode (pred, mode))
+                 s = add_decision (s, rtx_test::mode (e->pos), mode, true);
 
                /* Assign to operands[] first, so that the rtx usually doesn't
                   need to be live across the call to the predicate.
@@ -4045,19 +4155,21 @@ match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
                   since we fully expect to assign to operands[] at some point,
                   and since the caller usually writes to other parts of
                   recog_data anyway.  */
-               s = add_decision (s, test::set_op (e->pos, opno), true, false);
-               s = add_decision (s, test::predicate (e->pos, pred, mode),
+               s = add_decision (s, rtx_test::set_op (e->pos, opno),
+                                 true, false);
+               s = add_decision (s, rtx_test::predicate (e->pos, pred, mode),
                                  true, false);
              }
            else
              /* Historically we've ignored the mode when there's no
                 predicate.  Just set up operands[] unconditionally.  */
-             s = add_decision (s, test::set_op (e->pos, opno), true, false);
+             s = add_decision (s, rtx_test::set_op (e->pos, opno),
+                               true, false);
            break;
          }
 
        default:
-         s = add_decision (s, test::mode (e->pos),
+         s = add_decision (s, rtx_test::mode (e->pos),
                            GET_MODE (e->pattern), false);
          break;
        }
@@ -4065,7 +4177,7 @@ match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
 
   /* Finally add rtx_equal_p checks for duplicated operands.  */
   FOR_EACH_VEC_ELT (dup_tests, i, e)
-    s = add_decision (s, test::duplicate (e->pos, XINT (e->pattern, 0)),
+    s = add_decision (s, rtx_test::duplicate (e->pos, XINT (e->pattern, 0)),
                      true, false);
   return s;
 }
@@ -4074,55 +4186,52 @@ match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
 
    (1) the rtx doesn't match anything already matched by S
    (2) the rtx matches TOP_PATTERN and
-   (3) C_TEST is true.
+   (3) the C test required by INFO->def is true
 
-   For peephole2, TOP_PATTERN is the DEFINE_PEEPHOLE2 itself, otherwise
-   it is the rtx pattern to match (PARALLEL, SET, etc.).  */
+   For peephole2, TOP_PATTERN is a SEQUENCE of the instruction patterns
+   to match, otherwise it is a single instruction pattern.  */
 
 static void
-match_pattern_1 (state *s, rtx top_pattern, const char *c_test,
+match_pattern_1 (state *s, md_rtx_info *info, rtx pattern,
                 acceptance_type acceptance)
 {
-  if (GET_CODE (top_pattern) == DEFINE_PEEPHOLE2)
+  if (acceptance.type == PEEPHOLE2)
     {
       /* Match each individual instruction.  */
       position **subpos_ptr = &peep2_insn_pos_list;
       int count = 0;
-      for (int i = 0; i < XVECLEN (top_pattern, 0); ++i)
+      for (int i = 0; i < XVECLEN (pattern, 0); ++i)
        {
-         rtx x = XVECEXP (top_pattern, 0, i);
-         /* Ignore scratch register requirements.  */
-         if (GET_CODE (x) != MATCH_SCRATCH && GET_CODE (x) != MATCH_DUP)
-           {
-             position *subpos = next_position (subpos_ptr, &root_pos,
-                                               POS_PEEP2_INSN, count);
-             if (count > 0)
-               s = add_decision (s, test::peep2_count (count + 1),
-                                 true, false);
-             s = match_pattern_2 (s, top_pattern, subpos, x);
-             subpos_ptr = &subpos->next;
-             count += 1;
-           }
+         rtx x = XVECEXP (pattern, 0, i);
+         position *subpos = next_position (subpos_ptr, &root_pos,
+                                           POS_PEEP2_INSN, count);
+         if (count > 0)
+           s = add_decision (s, rtx_test::peep2_count (count + 1),
+                             true, false);
+         s = match_pattern_2 (s, info, subpos, x);
+         subpos_ptr = &subpos->next;
+         count += 1;
        }
       acceptance.u.full.u.match_len = count - 1;
     }
   else
     {
       /* Make the rtx itself.  */
-      s = match_pattern_2 (s, top_pattern, &root_pos, top_pattern);
+      s = match_pattern_2 (s, info, &root_pos, pattern);
 
       /* If the match is only valid when extra clobbers are added,
         make sure we're able to pass that information to the caller.  */
       if (acceptance.type == RECOG && acceptance.u.full.u.num_clobbers)
-       s = add_decision (s, test::have_num_clobbers (), true, false);
+       s = add_decision (s, rtx_test::have_num_clobbers (), true, false);
     }
 
   /* Make sure that the C test is true.  */
+  const char *c_test = get_c_test (info->def);
   if (maybe_eval_c_test (c_test) != 1)
-    s = add_decision (s, test::c_test (c_test), true, false);
+    s = add_decision (s, rtx_test::c_test (c_test), true, false);
 
   /* Accept the pattern.  */
-  add_decision (s, test::accept (acceptance), true, false);
+  add_decision (s, rtx_test::accept (acceptance), true, false);
 }
 
 /* Like match_pattern_1, but (if merge_states_p) try to merge the
@@ -4130,7 +4239,7 @@ match_pattern_1 (state *s, rtx top_pattern, const char *c_test,
    backtracking.  */
 
 static void
-match_pattern (state *s, rtx top_pattern, const char *c_test,
+match_pattern (state *s, md_rtx_info *info, rtx pattern,
               acceptance_type acceptance)
 {
   if (merge_states_p)
@@ -4138,11 +4247,11 @@ match_pattern (state *s, rtx top_pattern, const char *c_test,
       state root;
       /* Add the decisions to a fresh state and then merge the full tree
         into the existing one.  */
-      match_pattern_1 (&root, top_pattern, c_test, acceptance);
+      match_pattern_1 (&root, info, pattern, acceptance);
       merge_into_state (s, &root);
     }
   else
-    match_pattern_1 (s, top_pattern, c_test, acceptance);
+    match_pattern_1 (s, info, pattern, acceptance);
 }
 
 /* Begin the output file.  */
@@ -4154,32 +4263,27 @@ write_header (void)
 /* Generated automatically by the program `genrecog' from the target\n\
    machine description file.  */\n\
 \n\
+#define IN_TARGET_CODE 1\n\
+\n\
 #include \"config.h\"\n\
 #include \"system.h\"\n\
 #include \"coretypes.h\"\n\
-#include \"tm.h\"\n\
+#include \"backend.h\"\n\
+#include \"predict.h\"\n\
 #include \"rtl.h\"\n\
+#include \"memmodel.h\"\n\
 #include \"tm_p.h\"\n\
-#include \"hashtab.h\"\n\
-#include \"hash-set.h\"\n\
-#include \"vec.h\"\n\
-#include \"machmode.h\"\n\
-#include \"hard-reg-set.h\"\n\
-#include \"input.h\"\n\
-#include \"function.h\"\n\
+#include \"emit-rtl.h\"\n\
 #include \"insn-config.h\"\n\
 #include \"recog.h\"\n\
 #include \"output.h\"\n\
 #include \"flags.h\"\n\
-#include \"hard-reg-set.h\"\n\
-#include \"predict.h\"\n\
-#include \"basic-block.h\"\n\
+#include \"df.h\"\n\
 #include \"resource.h\"\n\
 #include \"diagnostic-core.h\"\n\
 #include \"reload.h\"\n\
 #include \"regs.h\"\n\
 #include \"tm-constrs.h\"\n\
-#include \"predict.h\"\n\
 \n");
 
   puts ("\n\
@@ -4232,6 +4336,9 @@ parameter_type_string (parameter::type_enum type)
     case parameter::INT:
       return "int";
 
+    case parameter::UINT:
+      return "unsigned int";
+
     case parameter::WIDE_INT:
       return "HOST_WIDE_INT";
     }
@@ -4278,7 +4385,7 @@ get_failure_return (routine_type type)
 
     case SPLIT:
     case PEEPHOLE2:
-      return "NULL_RTX";
+      return "NULL";
     }
   gcc_unreachable ();
 }
@@ -4293,8 +4400,9 @@ enum exit_state {
 
 /* Information used while writing out code.  */
 
-struct output_state
+class output_state
 {
+public:
   /* The type of routine that we're generating.  */
   routine_type type;
 
@@ -4320,7 +4428,7 @@ static bool
 terminal_pattern_p (decision *d, unsigned int *base_out,
                    unsigned int *count_out)
 {
-  if (d->test.kind != test::PATTERN)
+  if (d->test.kind != rtx_test::PATTERN)
     return false;
   unsigned int base = 0;
   unsigned int count = 0;
@@ -4329,7 +4437,7 @@ terminal_pattern_p (decision *d, unsigned int *base_out,
       if (trans->is_param || trans->labels.length () != 1)
        return false;
       decision *subd = trans->to->singleton ();
-      if (!subd || subd->test.kind != test::ACCEPT)
+      if (!subd || subd->test.kind != rtx_test::ACCEPT)
        return false;
       unsigned int this_base = (subd->test.u.acceptance.u.full.code
                                - trans->labels[0]);
@@ -4348,7 +4456,7 @@ terminal_pattern_p (decision *d, unsigned int *base_out,
    already available in state OS.  */
 
 static bool
-test_position_available_p (output_state *os, const test &test)
+test_position_available_p (output_state *os, const rtx_test &test)
 {
   return (!test.pos
          || test.pos_operand >= 0
@@ -4444,13 +4552,17 @@ print_parameter_value (const parameter &param)
        break;
 
       case parameter::MODE:
-       printf ("%smode", GET_MODE_NAME ((machine_mode) param.value));
+       printf ("E_%smode", GET_MODE_NAME ((machine_mode) param.value));
        break;
 
       case parameter::INT:
        printf ("%d", (int) param.value);
        break;
 
+      case parameter::UINT:
+       printf ("%u", (unsigned int) param.value);
+       break;
+
       case parameter::WIDE_INT:
        print_host_wide_int (param.value);
        break;
@@ -4460,7 +4572,7 @@ print_parameter_value (const parameter &param)
 /* Print the C expression for the rtx tested by TEST.  */
 
 static void
-print_test_rtx (output_state *os, const test &test)
+print_test_rtx (output_state *os, const rtx_test &test)
 {
   if (test.pos_operand >= 0)
     printf ("operands[%d]", test.pos_operand);
@@ -4471,41 +4583,53 @@ print_test_rtx (output_state *os, const test &test)
 /* Print the C expression for non-boolean test TEST.  */
 
 static void
-print_nonbool_test (output_state *os, const test &test)
+print_nonbool_test (output_state *os, const rtx_test &test)
 {
   switch (test.kind)
     {
-    case test::CODE:
+    case rtx_test::CODE:
       printf ("GET_CODE (");
       print_test_rtx (os, test);
       printf (")");
       break;
 
-    case test::MODE:
+    case rtx_test::MODE:
       printf ("GET_MODE (");
       print_test_rtx (os, test);
       printf (")");
       break;
 
-    case test::VECLEN:
+    case rtx_test::VECLEN:
       printf ("XVECLEN (");
       print_test_rtx (os, test);
       printf (", 0)");
       break;
 
-    case test::INT_FIELD:
+    case rtx_test::INT_FIELD:
       printf ("XINT (");
       print_test_rtx (os, test);
       printf (", %d)", test.u.opno);
       break;
 
-    case test::WIDE_INT_FIELD:
+    case rtx_test::REGNO_FIELD:
+      printf ("REGNO (");
+      print_test_rtx (os, test);
+      printf (")");
+      break;
+
+    case rtx_test::SUBREG_FIELD:
+      printf ("SUBREG_BYTE (");
+      print_test_rtx (os, test);
+      printf (")");
+      break;
+
+    case rtx_test::WIDE_INT_FIELD:
       printf ("XWINT (");
       print_test_rtx (os, test);
       printf (", %d)", test.u.opno);
       break;
 
-    case test::PATTERN:
+    case rtx_test::PATTERN:
       {
        pattern_routine *routine = test.u.pattern->routine;
        printf ("pattern%d (", routine->pattern_id);
@@ -4535,15 +4659,15 @@ print_nonbool_test (output_state *os, const test &test)
        break;
       }
 
-    case test::PEEP2_COUNT:
-    case test::VECLEN_GE:
-    case test::SAVED_CONST_INT:
-    case test::DUPLICATE:
-    case test::PREDICATE:
-    case test::SET_OP:
-    case test::HAVE_NUM_CLOBBERS:
-    case test::C_TEST:
-    case test::ACCEPT:
+    case rtx_test::PEEP2_COUNT:
+    case rtx_test::VECLEN_GE:
+    case rtx_test::SAVED_CONST_INT:
+    case rtx_test::DUPLICATE:
+    case rtx_test::PREDICATE:
+    case rtx_test::SET_OP:
+    case rtx_test::HAVE_NUM_CLOBBERS:
+    case rtx_test::C_TEST:
+    case rtx_test::ACCEPT:
       gcc_unreachable ();
     }
 }
@@ -4552,7 +4676,7 @@ print_nonbool_test (output_state *os, const test &test)
    decision performs TEST.  Print the C code for the label.  */
 
 static void
-print_label_value (const test &test, bool is_param, uint64_t value)
+print_label_value (const rtx_test &test, bool is_param, uint64_t value)
 {
   print_parameter_value (parameter (transition_parameter_type (test.kind),
                                    is_param, value));
@@ -4563,24 +4687,33 @@ print_label_value (const test &test, bool is_param, uint64_t value)
    Test for inequality if INVERT_P, otherwise test for equality.  */
 
 static void
-print_test (output_state *os, const test &test, bool is_param, uint64_t value,
-           bool invert_p)
+print_test (output_state *os, const rtx_test &test, bool is_param,
+           uint64_t value, bool invert_p)
 {
   switch (test.kind)
     {
       /* Handle the non-boolean TESTs.  */
-    case test::CODE:
-    case test::MODE:
-    case test::VECLEN:
-    case test::INT_FIELD:
-    case test::WIDE_INT_FIELD:
-    case test::PATTERN:
+    case rtx_test::CODE:
+    case rtx_test::MODE:
+    case rtx_test::VECLEN:
+    case rtx_test::REGNO_FIELD:
+    case rtx_test::INT_FIELD:
+    case rtx_test::WIDE_INT_FIELD:
+    case rtx_test::PATTERN:
       print_nonbool_test (os, test);
       printf (" %s ", invert_p ? "!=" : "==");
       print_label_value (test, is_param, value);
       break;
 
-    case test::SAVED_CONST_INT:
+    case rtx_test::SUBREG_FIELD:
+      printf ("%s (", invert_p ? "maybe_ne" : "known_eq");
+      print_nonbool_test (os, test);
+      printf (", ");
+      print_label_value (test, is_param, value);
+      printf (")");
+      break;
+
+    case rtx_test::SAVED_CONST_INT:
       gcc_assert (!is_param && value == 1);
       print_test_rtx (os, test);
       printf (" %s const_int_rtx[MAX_SAVED_CONST_INT + ",
@@ -4591,20 +4724,20 @@ print_test (output_state *os, const test &test, bool is_param, uint64_t value,
       printf ("]");
       break;
 
-    case test::PEEP2_COUNT:
+    case rtx_test::PEEP2_COUNT:
       gcc_assert (!is_param && value == 1);
       printf ("peep2_current_count %s %d", invert_p ? "<" : ">=",
              test.u.min_len);
       break;
 
-    case test::VECLEN_GE:
+    case rtx_test::VECLEN_GE:
       gcc_assert (!is_param && value == 1);
       printf ("XVECLEN (");
       print_test_rtx (os, test);
       printf (", 0) %s %d", invert_p ? "<" : ">=", test.u.min_len);
       break;
 
-    case test::PREDICATE:
+    case rtx_test::PREDICATE:
       gcc_assert (!is_param && value == 1);
       printf ("%s%s (", invert_p ? "!" : "", test.u.predicate.data->name);
       print_test_rtx (os, test);
@@ -4615,27 +4748,27 @@ print_test (output_state *os, const test &test, bool is_param, uint64_t value,
       printf (")");
       break;
 
-    case test::DUPLICATE:
+    case rtx_test::DUPLICATE:
       gcc_assert (!is_param && value == 1);
       printf ("%srtx_equal_p (", invert_p ? "!" : "");
       print_test_rtx (os, test);
       printf (", operands[%d])", test.u.opno);
       break;
 
-    case test::HAVE_NUM_CLOBBERS:
+    case rtx_test::HAVE_NUM_CLOBBERS:
       gcc_assert (!is_param && value == 1);
       printf ("pnum_clobbers %s NULL", invert_p ? "==" : "!=");
       break;
 
-    case test::C_TEST:
+    case rtx_test::C_TEST:
       gcc_assert (!is_param && value == 1);
       if (invert_p)
        printf ("!");
-      print_c_condition (test.u.string);
+      rtx_reader_ptr->print_c_condition (test.u.string);
       break;
 
-    case test::ACCEPT:
-    case test::SET_OP:
+    case rtx_test::ACCEPT:
+    case rtx_test::SET_OP:
       gcc_unreachable ();
     }
 }
@@ -4811,9 +4944,9 @@ print_decision (output_state *os, decision *d, unsigned int indent,
          return ES_FALLTHROUGH;
        }
     }
-  else if (d->test.kind == test::ACCEPT)
+  else if (d->test.kind == rtx_test::ACCEPT)
     return print_acceptance (d->test.u.acceptance, indent, is_final);
-  else if (d->test.kind == test::SET_OP)
+  else if (d->test.kind == rtx_test::SET_OP)
     {
       printf_indent (indent, "operands[%d] = ", d->test.u.opno);
       print_test_rtx (os, d->test);
@@ -4842,8 +4975,8 @@ print_decision (output_state *os, decision *d, unsigned int indent,
        {
          d = trans->to->singleton ();
          if (!d
-             || d->test.kind == test::ACCEPT
-             || d->test.kind == test::SET_OP
+             || d->test.kind == rtx_test::ACCEPT
+             || d->test.kind == rtx_test::SET_OP
              || !d->if_statement_p (&label)
              || !test_position_available_p (os, d->test))
            break;
@@ -4868,7 +5001,7 @@ print_decision (output_state *os, decision *d, unsigned int indent,
          return print_state (os, to, indent, is_final);
        }
       else if (to->singleton ()
-              && to->first->test.kind == test::ACCEPT
+              && to->first->test.kind == rtx_test::ACCEPT
               && single_statement_p (to->first->test.u.acceptance))
        {
          /* The target of the transition is a simple "return" statement.
@@ -5021,7 +5154,7 @@ print_subroutine_start (output_state *os, state *s, position *root)
   if (os->type == SUBPATTERN || os->type == RECOG)
     printf ("  int res ATTRIBUTE_UNUSED;\n");
   else
-    printf ("  rtx res ATTRIBUTE_UNUSED;\n");
+    printf ("  rtx_insn *res ATTRIBUTE_UNUSED;\n");
 }
 
 /* Output the definition of pattern routine ROUTINE.  */
@@ -5071,11 +5204,6 @@ print_pattern (output_state *os, pattern_routine *routine)
 static void
 print_subroutine (output_state *os, state *s, int proc_id)
 {
-  /* For now, the top-level functions take a plain "rtx", and perform a
-     checked cast to "rtx_insn *" for use throughout the rest of the
-     function and the code it calls.  */
-  const char *insn_param
-    = proc_id > 0 ? "rtx_insn *insn" : "rtx uncast_insn";
   printf ("\n");
   switch (os->type)
     {
@@ -5088,35 +5216,32 @@ print_subroutine (output_state *os, state *s, int proc_id)
       else
        printf ("int\nrecog");
       printf (" (rtx x1 ATTRIBUTE_UNUSED,\n"
-             "\t%s ATTRIBUTE_UNUSED,\n"
-             "\tint *pnum_clobbers ATTRIBUTE_UNUSED)\n", insn_param);
+             "\trtx_insn *insn ATTRIBUTE_UNUSED,\n"
+             "\tint *pnum_clobbers ATTRIBUTE_UNUSED)\n");
       break;
 
     case SPLIT:
       if (proc_id)
-       printf ("static rtx\nsplit_%d", proc_id);
+       printf ("static rtx_insn *\nsplit_%d", proc_id);
       else
-       printf ("rtx\nsplit_insns");
-      printf (" (rtx x1 ATTRIBUTE_UNUSED, %s ATTRIBUTE_UNUSED)\n",
-             insn_param);
+       printf ("rtx_insn *\nsplit_insns");
+      printf (" (rtx x1 ATTRIBUTE_UNUSED, rtx_insn *insn ATTRIBUTE_UNUSED)\n");
       break;
 
     case PEEPHOLE2:
       if (proc_id)
-       printf ("static rtx\npeephole2_%d", proc_id);
+       printf ("static rtx_insn *\npeephole2_%d", proc_id);
       else
-       printf ("rtx\npeephole2_insns");
+       printf ("rtx_insn *\npeephole2_insns");
       printf (" (rtx x1 ATTRIBUTE_UNUSED,\n"
-             "\t%s ATTRIBUTE_UNUSED,\n"
-             "\tint *pmatch_len_ ATTRIBUTE_UNUSED)\n", insn_param);
+             "\trtx_insn *insn ATTRIBUTE_UNUSED,\n"
+             "\tint *pmatch_len_ ATTRIBUTE_UNUSED)\n");
       break;
     }
   print_subroutine_start (os, s, &root_pos);
   if (proc_id == 0)
     {
-      printf ("  recog_data.insn = NULL_RTX;\n");
-      printf ("  rtx_insn *insn ATTRIBUTE_UNUSED;\n");
-      printf ("  insn = safe_as_a <rtx_insn *> (uncast_insn);\n");
+      printf ("  recog_data.insn = NULL;\n");
     }
   print_state (os, s, 2, true);
   printf ("}\n");
@@ -5145,20 +5270,29 @@ print_subroutine_group (output_state *os, routine_type type, state *root)
   print_subroutine (os, root, 0);
 }
 
-/* Return the rtx pattern specified by the list of rtxes in a
-   define_insn or define_split.  */
+/* Return the rtx pattern for the list of rtxes in a define_peephole2.  */
 
 static rtx
-add_implicit_parallel (rtvec vec)
+get_peephole2_pattern (md_rtx_info *info)
 {
-  if (GET_NUM_ELEM (vec) == 1)
-    return RTVEC_ELT (vec, 0);
-  else
+  int i, j;
+  rtvec vec = XVEC (info->def, 0);
+  rtx pattern = rtx_alloc (SEQUENCE);
+  XVEC (pattern, 0) = rtvec_alloc (GET_NUM_ELEM (vec));
+  for (i = j = 0; i < GET_NUM_ELEM (vec); i++)
     {
-      rtx pattern = rtx_alloc (PARALLEL);
-      XVEC (pattern, 0) = vec;
-      return pattern;
+      rtx x = RTVEC_ELT (vec, i);
+      /* Ignore scratch register requirements.  */
+      if (GET_CODE (x) != MATCH_SCRATCH && GET_CODE (x) != MATCH_DUP)
+       {
+         XVECEXP (pattern, 0, j) = x;
+         j++;
+       }
     }
+  XVECLEN (pattern, 0) = j;
+  if (j == 0)
+    error_at (info->loc, "empty define_peephole2");
+  return pattern;
 }
 
 /* Return true if *PATTERN_PTR is a PARALLEL in which at least one trailing
@@ -5205,9 +5339,8 @@ remove_clobbers (acceptance_type *acceptance_ptr, rtx *pattern_ptr)
 }
 
 int
-main (int argc, char **argv)
+main (int argc, const char **argv)
 {
-  rtx desc;
   state insn_root, split_root, peephole2_root;
 
   progname = "genrecog";
@@ -5215,61 +5348,61 @@ main (int argc, char **argv)
   if (!init_rtx_reader_args (argc, argv))
     return (FATAL_EXIT_CODE);
 
-  next_insn_code = 0;
-
   write_header ();
 
   /* Read the machine description.  */
 
-  while (1)
+  md_rtx_info info;
+  while (read_md_rtx (&info))
     {
-      desc = read_md_rtx (&pattern_lineno, &next_insn_code);
-      if (desc == NULL)
-       break;
-
-      rtx pattern;
+      rtx def = info.def;
 
       acceptance_type acceptance;
       acceptance.partial_p = false;
-      acceptance.u.full.code = next_insn_code;
+      acceptance.u.full.code = info.index;
 
-      switch (GET_CODE (desc))
+      rtx pattern;
+      switch (GET_CODE (def))
        {
        case DEFINE_INSN:
          {
            /* Match the instruction in the original .md form.  */
-           pattern = add_implicit_parallel (XVEC (desc, 1));
            acceptance.type = RECOG;
            acceptance.u.full.u.num_clobbers = 0;
-           match_pattern (&insn_root, pattern, XSTR (desc, 2), acceptance);
+           pattern = add_implicit_parallel (XVEC (def, 1));
+           validate_pattern (pattern, &info, NULL_RTX, 0);
+           match_pattern (&insn_root, &info, pattern, acceptance);
 
            /* If the pattern is a PARALLEL with trailing CLOBBERs,
               allow recog_for_combine to match without the clobbers.  */
            if (GET_CODE (pattern) == PARALLEL
                && remove_clobbers (&acceptance, &pattern))
-             match_pattern (&insn_root, pattern, XSTR (desc, 2), acceptance);
+             match_pattern (&insn_root, &info, pattern, acceptance);
            break;
          }
 
        case DEFINE_SPLIT:
          acceptance.type = SPLIT;
-         pattern = add_implicit_parallel (XVEC (desc, 0));
-         match_pattern (&split_root, pattern, XSTR (desc, 1), acceptance);
+         pattern = add_implicit_parallel (XVEC (def, 0));
+         validate_pattern (pattern, &info, NULL_RTX, 0);
+         match_pattern (&split_root, &info, pattern, acceptance);
 
          /* Declare the gen_split routine that we'll call if the
             pattern matches.  The definition comes from insn-emit.c.  */
-         printf ("extern rtx gen_split_%d (rtx_insn *, rtx *);\n",
-                 next_insn_code);
+         printf ("extern rtx_insn *gen_split_%d (rtx_insn *, rtx *);\n",
+                 info.index);
          break;
 
        case DEFINE_PEEPHOLE2:
          acceptance.type = PEEPHOLE2;
-         match_pattern (&peephole2_root, desc, XSTR (desc, 1), acceptance);
+         pattern = get_peephole2_pattern (&info);
+         validate_pattern (pattern, &info, NULL_RTX, 0);
+         match_pattern (&peephole2_root, &info, pattern, acceptance);
 
          /* Declare the gen_peephole2 routine that we'll call if the
             pattern matches.  The definition comes from insn-emit.c.  */
-         printf ("extern rtx gen_peephole2_%d (rtx_insn *, rtx *);\n",
-                 next_insn_code);
+         printf ("extern rtx_insn *gen_peephole2_%d (rtx_insn *, rtx *);\n",
+                 info.index);
          break;
 
        default: