]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/genrecog.c
PR fortran/95090 - ICE: identifier overflow
[thirdparty/gcc.git] / gcc / genrecog.c
index 217eb500751d02bed84b7395d78b2622bb365422..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 {
@@ -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 'r': 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 'r': 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 'r': 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.  */
@@ -1012,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;
 
@@ -1039,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;
 
@@ -1050,8 +1111,9 @@ struct pattern_use
 };
 
 /* Represents a test performed by a decision.  */
-struct rtx_test
+class rtx_test
 {
+public:
   rtx_test ();
 
   /* The types of test that can be performed.  Most of them take as input
@@ -1069,6 +1131,9 @@ struct rtx_test
     /* Check REGNO (X) == LABEL.  */
     REGNO_FIELD,
 
+    /* Check known_eq (SUBREG_BYTE (X), LABEL).  */
+    SUBREG_FIELD,
+
     /* Check XINT (X, u.opno) == LABEL.  */
     INT_FIELD,
 
@@ -1149,6 +1214,7 @@ struct rtx_test
   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 *);
@@ -1193,6 +1259,13 @@ rtx_test::regno_field (position *pos)
   return res;
 }
 
+rtx_test
+rtx_test::subreg_field (position *pos)
+{
+  rtx_test res (pos, rtx_test::SUBREG_FIELD);
+  return res;
+}
+
 rtx_test
 rtx_test::int_field (position *pos, int opno)
 {
@@ -1314,6 +1387,7 @@ operator == (const rtx_test &a, const rtx_test &b)
     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;
@@ -1358,8 +1432,9 @@ operator != (const rtx_test &a, const rtx_test &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 ();
@@ -1372,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);
 }
@@ -1421,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> *);
@@ -1465,8 +1543,9 @@ 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>
 {
+public:
   decision (const rtx_test &);
 
   void set_parent (list_head <decision> *s);
@@ -1485,8 +1564,9 @@ struct decision : list_head <transition>
 /* 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> *) {}
 };
 
@@ -1696,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;
@@ -1769,6 +1850,7 @@ safe_to_hoist_p (decision *d, const rtx_test &test, known_conditions *kc)
       gcc_unreachable ();
 
     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:
@@ -1976,6 +2058,7 @@ transition_parameter_type (rtx_test::kind_enum kind)
       return parameter::MODE;
 
     case rtx_test::REGNO_FIELD:
+    case rtx_test::SUBREG_FIELD:
       return parameter::UINT;
 
     case rtx_test::INT_FIELD:
@@ -2022,8 +2105,9 @@ find_operand_positions (state *s, vec <int> &operand_pos)
 }
 
 /* Statistics about a matching routine.  */
-struct stats
+class stats
 {
+public:
   stats ();
 
   /* The total number of decisions in the routine, excluding trivial
@@ -2159,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.  */
@@ -2183,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
@@ -2256,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.  */
@@ -2287,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.  */
@@ -2521,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 &);
 };
@@ -3406,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;
@@ -3788,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 *);
 
@@ -3811,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;
@@ -3852,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:
@@ -3869,16 +3946,13 @@ 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);
                  }
              }
 
@@ -4002,6 +4076,14 @@ match_pattern_2 (state *s, rtx top_pattern, position *pos, rtx pattern)
                                      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;
 
@@ -4063,7 +4145,7 @@ 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))
+               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
@@ -4104,13 +4186,13 @@ 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 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 (acceptance.type == PEEPHOLE2)
@@ -4118,15 +4200,15 @@ match_pattern_1 (state *s, rtx top_pattern, const char *c_test,
       /* 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);
+         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, top_pattern, subpos, x);
+         s = match_pattern_2 (s, info, subpos, x);
          subpos_ptr = &subpos->next;
          count += 1;
        }
@@ -4135,7 +4217,7 @@ match_pattern_1 (state *s, rtx top_pattern, const char *c_test,
   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.  */
@@ -4144,6 +4226,7 @@ match_pattern_1 (state *s, rtx top_pattern, const char *c_test,
     }
 
   /* 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, rtx_test::c_test (c_test), true, false);
 
@@ -4156,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)
@@ -4164,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.  */
@@ -4180,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\
@@ -4322,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;
 
@@ -4473,7 +4552,7 @@ 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:
@@ -4538,6 +4617,12 @@ print_nonbool_test (output_state *os, const rtx_test &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);
@@ -4620,6 +4705,14 @@ print_test (output_state *os, const rtx_test &test, bool is_param,
       print_label_value (test, is_param, value);
       break;
 
+    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);
@@ -4671,7 +4764,7 @@ print_test (output_state *os, const rtx_test &test, bool is_param,
       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 rtx_test::ACCEPT:
@@ -5111,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 "recog" takes a plain "rtx", and performs 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)
     {
@@ -5128,8 +5216,8 @@ 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:
@@ -5154,11 +5242,6 @@ print_subroutine (output_state *os, state *s, int proc_id)
   if (proc_id == 0)
     {
       printf ("  recog_data.insn = NULL;\n");
-      if (os->type == RECOG)
-       {
-         printf ("  rtx_insn *insn ATTRIBUTE_UNUSED;\n");
-         printf ("  insn = safe_as_a <rtx_insn *> (uncast_insn);\n");
-       }
     }
   print_state (os, s, 2, true);
   printf ("}\n");
@@ -5187,28 +5270,13 @@ 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.  */
-
-static rtx
-add_implicit_parallel (rtvec vec)
-{
-  if (GET_NUM_ELEM (vec) == 1)
-    return RTVEC_ELT (vec, 0);
-  else
-    {
-      rtx pattern = rtx_alloc (PARALLEL);
-      XVEC (pattern, 0) = vec;
-      return pattern;
-    }
-}
-
 /* Return the rtx pattern for the list of rtxes in a define_peephole2.  */
 
 static rtx
-get_peephole2_pattern (rtvec vec)
+get_peephole2_pattern (md_rtx_info *info)
 {
   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++)
@@ -5223,7 +5291,7 @@ get_peephole2_pattern (rtvec vec)
     }
   XVECLEN (pattern, 0) = j;
   if (j == 0)
-    error_with_line (pattern_lineno, "empty define_peephole2");
+    error_at (info->loc, "empty define_peephole2");
   return pattern;
 }
 
@@ -5271,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";
@@ -5281,64 +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 def = info.def;
 
       acceptance_type acceptance;
       acceptance.partial_p = false;
-      acceptance.u.full.code = next_insn_code;
+      acceptance.u.full.code = info.index;
 
       rtx pattern;
-      switch (GET_CODE (desc))
+      switch (GET_CODE (def))
        {
        case DEFINE_INSN:
          {
            /* Match the instruction in the original .md form.  */
            acceptance.type = RECOG;
            acceptance.u.full.u.num_clobbers = 0;
-           pattern = add_implicit_parallel (XVEC (desc, 1));
-           validate_pattern (pattern, desc, NULL_RTX, 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));
-         validate_pattern (pattern, desc, NULL_RTX, 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_insn *gen_split_%d (rtx_insn *, rtx *);\n",
-                 next_insn_code);
+                 info.index);
          break;
 
        case DEFINE_PEEPHOLE2:
          acceptance.type = PEEPHOLE2;
-         pattern = get_peephole2_pattern (XVEC (desc, 0));
-         validate_pattern (pattern, desc, NULL_RTX, 0);
-         match_pattern (&peephole2_root, pattern, 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_insn *gen_peephole2_%d (rtx_insn *, rtx *);\n",
-                 next_insn_code);
+                 info.index);
          break;
 
        default: