OSDN Git Service

* genrecog.c (*): Rename _last_insn to last_insn.
[pf3gnuchains/gcc-fork.git] / gcc / genrecog.c
index bc49d45..c86b62a 100644 (file)
@@ -1,5 +1,6 @@
 /* Generate code from machine description to recognize rtl as insns.
-   Copyright (C) 1987, 88, 92-95, 97-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
 
    This file is part of GNU CC.
 
@@ -115,6 +116,7 @@ struct decision_test
 
     struct {
       int code_number;         /* Insn number matched.  */
+      int lineno;              /* Line number of the insn.  */
       int num_clobbers_to_add; /* Number of CLOBBERs to be added.  */
     } insn;
   } u;
@@ -170,6 +172,12 @@ static int next_index;
    allocate in each subroutine we make.  */
 
 static int max_depth;
+
+/* The line number of the start of the pattern currently being processed.  */
+static int pattern_lineno;
+
+/* Count of errors.  */
+static int error_count;
 \f
 /* This table contains a list of the rtl codes that can possibly match a
    predicate defined in recog.c.  The function `maybe_both_true' uses it to
@@ -190,6 +198,7 @@ static struct pred_table
   {"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
                       LABEL_REF, SUBREG, REG, MEM, PLUS, MINUS, MULT}},
   {"register_operand", {SUBREG, REG}},
+  {"pmode_register_operand", {SUBREG, REG}},
   {"scratch_operand", {SCRATCH, REG}},
   {"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
                         LABEL_REF}},
@@ -209,80 +218,124 @@ static struct pred_table
 
 #define NUM_KNOWN_PREDS (sizeof preds / sizeof preds[0])
 
+static const char * special_mode_pred_table[] = {
+#ifdef SPECIAL_MODE_PREDICATES
+  SPECIAL_MODE_PREDICATES
+#endif
+  "pmode_register_operand"
+};
+
+#define NUM_SPECIAL_MODE_PREDS \
+  (sizeof (special_mode_pred_table) / sizeof (special_mode_pred_table[0]))
+
+static void message_with_line
+  PARAMS ((int, const char *, ...)) ATTRIBUTE_PRINTF_2;
+
 static struct decision *new_decision
-  PROTO((const char *, struct decision_head *));
+  PARAMS ((const char *, struct decision_head *));
 static struct decision_test *new_decision_test
-  PROTO((enum decision_type, struct decision_test ***));
+  PARAMS ((enum decision_type, struct decision_test ***));
+static rtx find_operand
+  PARAMS ((rtx, int));
+static void validate_pattern
+  PARAMS ((rtx, rtx, rtx));
 static struct decision *add_to_sequence
-  PROTO((rtx, struct decision_head *, const char *, enum routine_type, int));
+  PARAMS ((rtx, struct decision_head *, const char *, enum routine_type, int));
 
 static int maybe_both_true_2
-  PROTO((struct decision_test *, struct decision_test *));
+  PARAMS ((struct decision_test *, struct decision_test *));
 static int maybe_both_true_1
-  PROTO((struct decision_test *, struct decision_test *));
+  PARAMS ((struct decision_test *, struct decision_test *));
 static int maybe_both_true
-  PROTO((struct decision *, struct decision *, int));
+  PARAMS ((struct decision *, struct decision *, int));
 
 static int nodes_identical_1
-  PROTO((struct decision_test *, struct decision_test *));
+  PARAMS ((struct decision_test *, struct decision_test *));
 static int nodes_identical
-  PROTO((struct decision *, struct decision *));
+  PARAMS ((struct decision *, struct decision *));
 static void merge_accept_insn
-  PROTO((struct decision *, struct decision *));
+  PARAMS ((struct decision *, struct decision *));
 static void merge_trees
-  PROTO((struct decision_head *, struct decision_head *));
+  PARAMS ((struct decision_head *, struct decision_head *));
 
 static void factor_tests
-  PROTO((struct decision_head *));
+  PARAMS ((struct decision_head *));
 static void simplify_tests
-  PROTO((struct decision_head *));
+  PARAMS ((struct decision_head *));
 static int break_out_subroutines
-  PROTO((struct decision_head *, int));
+  PARAMS ((struct decision_head *, int));
 static void find_afterward
-  PROTO((struct decision_head *, struct decision *));
+  PARAMS ((struct decision_head *, struct decision *));
 
 static void change_state
-  PROTO((const char *, const char *, struct decision *, const char *));
+  PARAMS ((const char *, const char *, struct decision *, const char *));
 static void print_code
-  PROTO((enum rtx_code));
+  PARAMS ((enum rtx_code));
 static void write_afterward
-  PROTO((struct decision *, struct decision *, const char *));
+  PARAMS ((struct decision *, struct decision *, const char *));
 static struct decision *write_switch
-  PROTO((struct decision *, int));
+  PARAMS ((struct decision *, int));
 static void write_cond
-  PROTO((struct decision_test *, int, enum routine_type));
+  PARAMS ((struct decision_test *, int, enum routine_type));
 static void write_action
-  PROTO((struct decision_test *, int, int, struct decision *,
+  PARAMS ((struct decision_test *, int, int, struct decision *,
         enum routine_type));
 static int is_unconditional
-  PROTO((struct decision_test *, enum routine_type));
+  PARAMS ((struct decision_test *, enum routine_type));
 static int write_node
-  PROTO((struct decision *, int, enum routine_type));
+  PARAMS ((struct decision *, int, enum routine_type));
 static void write_tree_1
-  PROTO((struct decision_head *, int, enum routine_type));
+  PARAMS ((struct decision_head *, int, enum routine_type));
 static void write_tree
-  PROTO((struct decision_head *, const char *, enum routine_type, int));
+  PARAMS ((struct decision_head *, const char *, enum routine_type, int));
 static void write_subroutine
-  PROTO((struct decision_head *, enum routine_type));
+  PARAMS ((struct decision_head *, enum routine_type));
 static void write_subroutines
-  PROTO((struct decision_head *, enum routine_type));
+  PARAMS ((struct decision_head *, enum routine_type));
 static void write_header
-  PROTO((void));
+  PARAMS ((void));
 
 static struct decision_head make_insn_sequence
-  PROTO((rtx, enum routine_type));
+  PARAMS ((rtx, enum routine_type));
 static void process_tree
-  PROTO((struct decision_head *, enum routine_type));
+  PARAMS ((struct decision_head *, enum routine_type));
   
 static void record_insn_name
-  PROTO((int, const char *));
+  PARAMS ((int, const char *));
 
+static void debug_decision_0
+  PARAMS ((struct decision *, int, int));
 static void debug_decision_1
-  PROTO((struct decision *, int));
+  PARAMS ((struct decision *, int));
 static void debug_decision_2
-  PROTO((struct decision_test *));
+  PARAMS ((struct decision_test *));
 extern void debug_decision
-  PROTO((struct decision *));
+  PARAMS ((struct decision *));
+extern void debug_decision_list
+  PARAMS ((struct decision *));
+\f
+static void
+message_with_line VPARAMS ((int lineno, const char *msg, ...))
+{
+#ifndef ANSI_PROTOTYPES
+  int lineno;
+  const char *msg;
+#endif
+  va_list ap;
+
+  VA_START (ap, msg);
+
+#ifndef ANSI_PROTOTYPES
+  lineno = va_arg (ap, int);
+  msg = va_arg (ap, const char *);
+#endif
+
+  fprintf (stderr, "%s:%d: ", read_rtx_filename, lineno);
+  vfprintf (stderr, msg, ap);
+  fputc ('\n', stderr);
+
+  va_end (ap);
+}
 \f
 /* Create a new node in sequence after LAST.  */
 
@@ -324,6 +377,300 @@ new_decision_test (type, pplace)
   return test;
 }
 
+/* Search for and return operand N.  */
+
+static rtx
+find_operand (pattern, n)
+     rtx pattern;
+     int n;
+{
+  const char *fmt;
+  RTX_CODE code;
+  int i, j, len;
+  rtx r;
+
+  code = GET_CODE (pattern);
+  if ((code == MATCH_SCRATCH
+       || code == MATCH_INSN
+       || code == MATCH_OPERAND
+       || code == MATCH_OPERATOR
+       || code == MATCH_PARALLEL)
+      && XINT (pattern, 0) == n)
+    return pattern;
+
+  fmt = GET_RTX_FORMAT (code);
+  len = GET_RTX_LENGTH (code);
+  for (i = 0; i < len; i++)
+    {
+      switch (fmt[i])
+       {
+       case 'e': case 'u':
+         if ((r = find_operand (XEXP (pattern, i), n)) != NULL_RTX)
+           return r;
+         break;
+
+       case 'E':
+         for (j = 0; j < XVECLEN (pattern, i); j++)
+           if ((r = find_operand (XVECEXP (pattern, i, j), n)) != NULL_RTX)
+             return r;
+         break;
+
+       case 'i': case 'w': case '0': case 's':
+         break;
+
+       default:
+         abort ();
+       }
+    }
+
+  return NULL;
+}
+
+/* Check for various errors in patterns.  SET is nonnull for a destination,
+   and is the complete set pattern.  */
+
+static void
+validate_pattern (pattern, insn, set)
+     rtx pattern;
+     rtx insn;
+     rtx set;
+{
+  const char *fmt;
+  RTX_CODE code;
+  size_t i, len;
+  int j;
+
+  code = GET_CODE (pattern);
+  switch (code)
+    {
+    case MATCH_SCRATCH:
+      return;
+
+    case MATCH_INSN:
+    case MATCH_OPERAND:
+    case MATCH_OPERATOR:
+      {
+       const char *pred_name = XSTR (pattern, 1);
+       int allows_non_lvalue = 1, allows_non_const = 1;
+       int special_mode_pred = 0;
+       const char *c_test;
+
+       if (GET_CODE (insn) == DEFINE_INSN)
+         c_test = XSTR (insn, 2);
+       else
+         c_test = XSTR (insn, 1);
+
+       if (pred_name[0] != 0)
+         {
+           for (i = 0; i < NUM_KNOWN_PREDS; i++)
+             if (! strcmp (preds[i].name, pred_name))
+               break;
+
+           if (i < NUM_KNOWN_PREDS)
+             {
+               int j;
+
+               allows_non_lvalue = allows_non_const = 0;
+               for (j = 0; preds[i].codes[j] != 0; j++)
+                 {
+                   RTX_CODE c = preds[i].codes[j];
+                   if (c != LABEL_REF
+                       && c != SYMBOL_REF
+                       && c != CONST_INT
+                       && c != CONST_DOUBLE
+                       && c != CONST
+                       && c != HIGH
+                       && c != CONSTANT_P_RTX)
+                     allows_non_const = 1;
+
+                   if (c != REG
+                       && c != SUBREG
+                       && c != MEM
+                       && c != CONCAT
+                       && c != PARALLEL
+                       && c != STRICT_LOW_PART)
+                     allows_non_lvalue = 1;
+                 }
+             }
+           else
+             {
+#ifdef PREDICATE_CODES
+               /* If the port has a list of the predicates it uses but
+                  omits one, warn.  */
+               message_with_line (pattern_lineno,
+                                  "warning: `%s' not in PREDICATE_CODES",
+                                  pred_name);
+#endif
+             }
+
+           for (i = 0; i < NUM_SPECIAL_MODE_PREDS; ++i)
+             if (strcmp (pred_name, special_mode_pred_table[i]) == 0)
+               {
+                 special_mode_pred = 1;
+                 break;
+               }
+         }
+
+       /* A MATCH_OPERAND that is a SET should have an output reload.  */
+       if (set
+           && code == MATCH_OPERAND
+           && XSTR (pattern, 2)[0] != '\0'
+           && XSTR (pattern, 2)[0] != '='
+           && XSTR (pattern, 2)[0] != '+')
+         {
+           message_with_line (pattern_lineno,
+                              "operand %d missing output reload", 
+                              XINT (pattern, 0));
+           error_count++;
+         }
+
+       /* Allowing non-lvalues in destinations -- particularly CONST_INT --
+          while not likely to occur at runtime, results in less efficient
+          code from insn-recog.c.  */
+       if (set
+           && pred_name[0] != '\0'
+           && allows_non_lvalue)
+         {
+           message_with_line (pattern_lineno,
+                       "warning: 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 mistake.  Only DEFINE_INSN is eligible, since SPLIT
+          and PEEP2 can FAIL within the output pattern.  Exclude 
+          address_operand, since its mode is related to the mode of
+          the memory not the operand.  Exclude the SET_DEST of a call
+          instruction, as that is a common idiom.  */
+
+       if (GET_MODE (pattern) == VOIDmode
+           && code == MATCH_OPERAND
+           && GET_CODE (insn) == DEFINE_INSN
+           && allows_non_const
+           && ! special_mode_pred
+           && pred_name[0] != '\0'
+           && strcmp (pred_name, "address_operand") != 0
+           && strstr (c_test, "operands") == NULL
+           && ! (set
+                 && GET_CODE (set) == SET
+                 && GET_CODE (SET_SRC (set)) == CALL))
+         {
+           message_with_line (pattern_lineno,
+                              "warning: operand %d missing mode?",
+                              XINT (pattern, 0));
+         }
+       return;
+      }
+
+    case SET:
+      {
+       enum machine_mode dmode, smode;
+       rtx dest, src;
+
+       dest = SET_DEST (pattern);
+       src = SET_SRC (pattern);
+
+       /* Find the referant for a DUP.  */
+
+       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));
+
+       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));
+
+       /* STRICT_LOW_PART is a wrapper.  Its argument is the real
+          destination, and it's mode should match the source.  */
+       if (GET_CODE (dest) == STRICT_LOW_PART)
+         dest = XEXP (dest, 0);
+
+       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"))
+         ;
+
+        /* The operands of a SET must have the same mode unless one
+          is VOIDmode.  */
+        else if (dmode != VOIDmode && smode != VOIDmode && dmode != smode)
+         {
+           message_with_line (pattern_lineno,
+                              "mode mismatch in set: %smode vs %smode",
+                              GET_MODE_NAME (dmode), GET_MODE_NAME (smode));
+           error_count++;
+         }
+
+       /* If only one of the operands is VOIDmode, and PC or CC0 is 
+          not involved, it's probably a mistake.  */
+       else if (dmode != smode
+                && GET_CODE (dest) != PC
+                && GET_CODE (dest) != CC0
+                && GET_CODE (src) != PC
+                && GET_CODE (src) != CC0
+                && GET_CODE (src) != CONST_INT)
+         {
+           const char *which;
+           which = (dmode == VOIDmode ? "destination" : "source");
+           message_with_line (pattern_lineno,
+                              "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);
+        return;
+      }
+
+    case CLOBBER:
+      validate_pattern (SET_DEST (pattern), insn, pattern);
+      return;
+
+    case LABEL_REF:
+      if (GET_MODE (XEXP (pattern, 0)) != VOIDmode)
+       {
+         message_with_line (pattern_lineno,
+                            "operand to label_ref %smode not VOIDmode",
+                            GET_MODE_NAME (GET_MODE (XEXP (pattern, 0))));
+         error_count++;
+       }
+      break;
+
+    default:
+      break;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  len = GET_RTX_LENGTH (code);
+  for (i = 0; i < len; i++)
+    {
+      switch (fmt[i])
+       {
+       case 'e': case 'u':
+         validate_pattern (XEXP (pattern, i), insn, NULL_RTX);
+         break;
+
+       case 'E':
+         for (j = 0; j < XVECLEN (pattern, i); j++)
+           validate_pattern (XVECEXP (pattern, i, j), insn, NULL_RTX);
+         break;
+
+       case 'i': case 'w': case '0': case 's':
+         break;
+
+       default:
+         abort ();
+       }
+    }
+}
+
 /* Create a chain of nodes to verify that an rtl expression matches
    PATTERN.
 
@@ -465,15 +812,7 @@ add_to_sequence (pattern, last, position, insn_type, top)
                    }
              }
            else
-             {
-               test->u.pred.index = -1;
-#ifdef PREDICATE_CODES
-               /* If the port has a list of the predicates it uses but
-                  omits one, warn.  */
-               fprintf (stderr, "Warning: `%s' not in PREDICATE_CODES\n",
-                        pred_name);
-#endif
-             }
+             test->u.pred.index = -1;
          }
 
        /* Can't enforce a mode if we allow const_int.  */
@@ -526,32 +865,6 @@ add_to_sequence (pattern, last, position, insn_type, top)
       pattern = XEXP (pattern, 0);
       goto restart;
 
-    case SET:
-      /* The operands of a SET must have the same mode unless one
-        is VOIDmode.  */
-      if (GET_MODE (SET_SRC (pattern)) != VOIDmode
-         && GET_MODE (SET_DEST (pattern)) != VOIDmode
-         && GET_MODE (SET_SRC (pattern)) != GET_MODE (SET_DEST (pattern))
-         /* The mode of an ADDRESS_OPERAND is the mode of the memory
-            reference, not the mode of the address.  */
-         && ! (GET_CODE (SET_SRC (pattern)) == MATCH_OPERAND
-               && ! strcmp (XSTR (SET_SRC (pattern), 1), "address_operand")))
-       {
-         print_rtl (stderr, pattern);
-         fputc ('\n', stderr);
-         fatal ("mode mismatch in SET");
-       }
-      break;
-      
-    case LABEL_REF:
-      if (GET_MODE (XEXP (pattern, 0)) != VOIDmode)
-       {
-         print_rtl (stderr, pattern);
-         fputc ('\n', stderr);
-         fatal ("operand to LABEL_REF not VOIDmode");
-       }
-      break;
-
     default:
       break;
     }
@@ -700,15 +1013,18 @@ maybe_both_true_2 (d1, d2)
        {
          if (d2->type == DT_mode)
            {
-             if (d1->u.pred.mode != d2->u.mode)
-               return 0;
-           }
-         else if (d2->type == DT_pred)
-           {
-             if (d2->u.pred.mode != VOIDmode
-                 && d1->u.pred.mode != d2->u.pred.mode)
+             if (d1->u.pred.mode != d2->u.mode
+                 /* The mode of an address_operand predicate is the
+                    mode of the memory, not the operand.  It can only
+                    be used for testing the predicate, so we must
+                    ignore it here.  */
+                 && strcmp (d1->u.pred.name, "address_operand") != 0)
                return 0;
            }
+         /* Don't check two predicate modes here, because if both predicates
+            accept CONST_INT, then both can still be true even if the modes
+            are different.  If they don't accept CONST_INT, there will be a
+            separate DT_mode that will make maybe_both_true_1 return 0.  */
        }
 
       if (d1->u.pred.index >= 0)
@@ -922,7 +1238,17 @@ nodes_identical (d1, d2)
     }
 
   /* For success, they should now both be null.  */
-  return t1 == t2;
+  if (t1 != t2)
+    return 0;
+
+  /* Check that their subnodes are at the same position, as any one set
+     of sibling decisions must be at the same position.  */
+  if (d1->success.first
+      && d2->success.first
+      && strcmp (d1->success.first->position, d2->success.first->position))
+    return 0;
+
+  return 1;
 }
 
 /* A subroutine of merge_trees; given two nodes that have been declared
@@ -966,11 +1292,12 @@ merge_accept_insn (oldd, addd)
     }
   else
     {
-      fatal ("Two actions at one point in tree for insns \"%s\" (%d) and \"%s\" (%d)",
-            get_insn_name (old->u.insn.code_number),
-            old->u.insn.code_number,
-            get_insn_name (add->u.insn.code_number),
-            add->u.insn.code_number);
+      message_with_line (add->u.insn.lineno, "`%s' matches `%s'",
+                        get_insn_name (add->u.insn.code_number),
+                        get_insn_name (old->u.insn.code_number));
+      message_with_line (old->u.insn.lineno, "previous definition of `%s'",
+                        get_insn_name (old->u.insn.code_number));
+      error_count++;
     }
 }
 
@@ -1276,13 +1603,13 @@ change_state (oldpos, newpos, afterward, indent)
   for (old_has_insn = odepth - 1; old_has_insn >= 0; --old_has_insn)
     if (oldpos[old_has_insn] >= 'A' && oldpos[old_has_insn] <= 'Z')
       break;
-  for (new_has_insn = odepth - 1; new_has_insn >= 0; --new_has_insn)
+  for (new_has_insn = ndepth - 1; new_has_insn >= 0; --new_has_insn)
     if (newpos[new_has_insn] >= 'A' && newpos[new_has_insn] <= 'Z')
       break;
 
-  /* Make sure to reset the _last_insn pointer when popping back up.  */
+  /* Make sure to reset the last_insn pointer when popping back up.  */
   if (old_has_insn >= 0 && new_has_insn < 0)
-    printf ("%s_last_insn = insn;\n", indent);
+    printf ("%slast_insn = insn;\n", indent);
 
   /* Go down to desired level.  */
   while (depth < ndepth)
@@ -1293,7 +1620,7 @@ change_state (oldpos, newpos, afterward, indent)
          /* We can only fail if we're moving down the tree.  */
          if (old_has_insn >= 0 && oldpos[old_has_insn] >= newpos[depth])
            {
-             printf ("%s_last_insn = recog_next_insn (insn, %d);\n", 
+             printf ("%slast_insn = recog_next_insn (insn, %d);\n", 
                      indent, newpos[depth] - 'A');
            }
          else
@@ -1305,9 +1632,9 @@ change_state (oldpos, newpos, afterward, indent)
                printf ("%s  goto L%d;\n", indent, afterward->number);
              else
                printf ("%s  goto ret0;\n", indent);
-             printf ("%s_last_insn = tem;\n", indent);
+             printf ("%slast_insn = tem;\n", indent);
            }
-         printf ("%sx%d = PATTERN (_last_insn);\n", indent, depth + 1);
+         printf ("%sx%d = PATTERN (last_insn);\n", indent, depth + 1);
        }
       else if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
        printf ("%sx%d = XVECEXP (x%d, 0, %d);\n",
@@ -1374,13 +1701,14 @@ write_switch (start, depth)
     {
       char codemap[NUM_RTX_CODE];
       struct decision *ret;
+      RTX_CODE code;
 
       memset (codemap, 0, sizeof(codemap));
 
       printf ("  switch (GET_CODE (x%d))\n    {\n", depth);
+      code = p->tests->u.code;
       do 
        {
-         RTX_CODE code = p->tests->u.code;
          printf ("    case ");
          print_code (code);
          printf (":\n      goto L%d;\n", p->success.first->number);
@@ -1389,7 +1717,10 @@ write_switch (start, depth)
          codemap[code] = 1;
          p = p->next;
        }
-      while (p && p->tests->type == DT_code && !p->tests->next);
+      while (p
+            && ! p->tests->next
+            && p->tests->type == DT_code
+            && ! codemap[code = p->tests->u.code]);
 
       /* If P is testing a predicate that we know about and we haven't
         seen any of the codes that are valid for the predicate, we can
@@ -1451,30 +1782,29 @@ write_switch (start, depth)
           || type == DT_elt_one_int
           || type == DT_elt_zero_wide)
     {
-      const char *str;
-
       printf ("  switch (");
       switch (type)
        {
        case DT_mode:
-         str = "GET_MODE (x%d)";
+         printf ("GET_MODE (x%d)", depth);
          break;
        case DT_veclen:
-         str = "XVECLEN (x%d, 0)";
+         printf ("XVECLEN (x%d, 0)", depth);
          break;
        case DT_elt_zero_int:
-         str = "XINT (x%d, 0)";
+         printf ("XINT (x%d, 0)", depth);
          break;
        case DT_elt_one_int:
-         str = "XINT (x%d, 1)";
+         printf ("XINT (x%d, 1)", depth);
          break;
        case DT_elt_zero_wide:
-         str = "XWINT (x%d, 0)";
+         /* Convert result of XWINT to int for portability since some C
+            compilers won't do it and some will.  */
+         printf ("(int) XWINT (x%d, 0)", depth);
          break;
        default:
          abort ();
        }
-      printf (str, depth);
       printf (")\n    {\n");
 
       do
@@ -1834,32 +2164,7 @@ write_subroutine (head, type)
      struct decision_head *head;
      enum routine_type type;
 {
-  static const char * const proto_pattern[] = {
-    "%sint recog%s PROTO ((rtx, rtx, int *));\n",
-    "%srtx split%s PROTO ((rtx, rtx));\n",
-    "%srtx peephole2%s PROTO ((rtx, rtx, rtx *));\n"
-  };
-
-  static const char * const decl_pattern[] = {
-"%sint\n\
-recog%s (x0, insn, pnum_clobbers)\n\
-     register rtx x0;\n\
-     rtx insn ATTRIBUTE_UNUSED;\n\
-     int *pnum_clobbers ATTRIBUTE_UNUSED;\n",
-
-"%srtx\n\
-split%s (x0, insn)\n\
-     register rtx x0;\n\
-     rtx insn ATTRIBUTE_UNUSED;\n",
-
-"%srtx\n\
-peephole2%s (x0, insn, _plast_insn)\n\
-     register rtx x0;\n\
-     rtx insn ATTRIBUTE_UNUSED;\n\
-     rtx *_plast_insn ATTRIBUTE_UNUSED;\n"
-  };
-     
-  int subfunction = head->first->subroutine_number;
+  int subfunction = head->first ? head->first->subroutine_number : 0;
   const char *s_or_e;
   char extension[32];
   int i;
@@ -1873,21 +2178,48 @@ peephole2%s (x0, insn, _plast_insn)\n\
   else
     strcpy (extension, "_insns");
 
-  printf (proto_pattern[type], s_or_e, extension);
-  printf (decl_pattern[type], s_or_e, extension);
+  switch (type)
+    {
+    case RECOG:
+      printf ("%sint recog%s PARAMS ((rtx, rtx, int *));\n", s_or_e, extension);
+      printf ("%sint\n\
+recog%s (x0, insn, pnum_clobbers)\n\
+     register rtx x0;\n\
+     rtx insn ATTRIBUTE_UNUSED;\n\
+     int *pnum_clobbers ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+      break;
+    case SPLIT:
+      printf ("%srtx split%s PARAMS ((rtx, rtx));\n", s_or_e, extension);
+      printf ("%srtx\n\
+split%s (x0, insn)\n\
+     register rtx x0;\n\
+     rtx insn ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+      break;
+    case PEEPHOLE2:
+      printf ("%srtx peephole2%s PARAMS ((rtx, rtx, rtx *));\n", s_or_e, extension);
+      printf ("%srtx\n\
+peephole2%s (x0, insn, _plast_insn)\n\
+     register rtx x0;\n\
+     rtx insn ATTRIBUTE_UNUSED;\n\
+     rtx *_plast_insn ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+      break;
+    }
 
-  printf ("{\n  register rtx * const operands = &recog_data.operand[0];\n");
+  printf ("{\n  register rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];\n");
   for (i = 1; i <= max_depth; i++)
     printf ("  register rtx x%d ATTRIBUTE_UNUSED;\n", i);
 
   if (type == PEEPHOLE2)
-    printf ("  register rtx _last_insn = insn;\n");
+    printf ("  register rtx last_insn = insn;\n");
   printf ("  %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int");
 
-  write_tree (head, "", type, 1);
+  if (head->first)
+    write_tree (head, "", type, 1);
+  else
+    printf ("  goto ret0;\n");
 
   if (type == PEEPHOLE2)
-    printf (" ret1:\n  *_plast_insn = _last_insn;\n  return tem;\n");
+    printf (" ret1:\n  *_plast_insn = last_insn;\n  return tem;\n");
   printf (" ret0:\n  return %d;\n}\n\n", IS_SPLIT (type) ? 0 : -1);
 }
 
@@ -1978,6 +2310,7 @@ make_insn_sequence (insn, type)
   struct decision *last;
   struct decision_test *test, **place;
   struct decision_head head;
+  char *c_test_pos = "";
 
   record_insn_name (next_insn_code, (type == RECOG ? XSTR (insn, 0) : NULL));
 
@@ -2002,6 +2335,10 @@ make_insn_sequence (insn, type)
            }
        }
       XVECLEN (x, 0) = j;
+
+      c_test_pos = alloca (2);
+      c_test_pos[0] = 'A' + j - 1;
+      c_test_pos[1] = '\0';
     }
   else if (XVECLEN (insn, type == RECOG) == 1)
     x = XVECEXP (insn, type == RECOG, 0);
@@ -2012,6 +2349,8 @@ make_insn_sequence (insn, type)
       PUT_MODE (x, VOIDmode);
     }
 
+  validate_pattern (x, insn, NULL_RTX);
+
   memset(&head, 0, sizeof(head));
   last = add_to_sequence (x, &head, "", type, 1);
 
@@ -2025,7 +2364,7 @@ make_insn_sequence (insn, type)
       /* Need a new node if we have another test to add.  */
       if (test->type == DT_accept_op)
        {
-         last = new_decision ("", &last->success);
+         last = new_decision (c_test_pos, &last->success);
          place = &last->tests;
        }
       test = new_decision_test (DT_c_test, &place);
@@ -2034,6 +2373,7 @@ make_insn_sequence (insn, type)
 
   test = new_decision_test (DT_accept_insn, &place);
   test->u.insn.code_number = next_insn_code;
+  test->u.insn.lineno = pattern_lineno;
   test->u.insn.num_clobbers_to_add = 0;
 
   switch (type)
@@ -2100,6 +2440,7 @@ make_insn_sequence (insn, type)
 
              test = new_decision_test (DT_accept_insn, &place);
              test->u.insn.code_number = next_insn_code;
+             test->u.insn.lineno = pattern_lineno;
              test->u.insn.num_clobbers_to_add = XVECLEN (x, 0) - i;
 
              merge_trees (&head, &clobber_head);
@@ -2109,12 +2450,12 @@ make_insn_sequence (insn, type)
 
     case SPLIT:
       /* Define the subroutine we will call below and emit in genemit.  */
-      printf ("extern rtx gen_split_%d PROTO ((rtx *));\n", next_insn_code);
+      printf ("extern rtx gen_split_%d PARAMS ((rtx *));\n", next_insn_code);
       break;
 
     case PEEPHOLE2:
       /* Define the subroutine we will call below and emit in genemit.  */
-      printf ("extern rtx gen_peephole2_%d PROTO ((rtx, rtx *));\n",
+      printf ("extern rtx gen_peephole2_%d PARAMS ((rtx, rtx *));\n",
              next_insn_code);
       break;
     }
@@ -2129,19 +2470,32 @@ process_tree (head, subroutine_type)
      enum routine_type subroutine_type;
 {
   if (head->first == NULL)
-    return;
+    {
+      /* We can elide peephole2_insns, but not recog or split_insns.  */
+      if (subroutine_type == PEEPHOLE2)
+       return;
+    }
+  else
+    {
+      factor_tests (head);
+
+      next_subroutine_number = 0;
+      break_out_subroutines (head, 1);
+      find_afterward (head, NULL);
 
-  factor_tests (head);
-  simplify_tests (head);
+      /* We run this after find_afterward, because find_afterward needs
+        the redundant DT_mode tests on predicates to determine whether
+        two tests can both be true or not.  */
+      simplify_tests(head);
 
-  next_subroutine_number = 0;
-  break_out_subroutines (head, 1);
-  find_afterward (head, NULL);
+      write_subroutines (head, subroutine_type);
+    }
 
-  write_subroutines (head, subroutine_type);
   write_subroutine (head, subroutine_type);
 }
 \f
+extern int main PARAMS ((int, char **));
+
 int
 main (argc, argv)
      int argc;
@@ -2168,6 +2522,7 @@ main (argc, argv)
       perror (argv[1]);
       return FATAL_EXIT_CODE;
     }
+  read_rtx_filename = argv[1];
 
   next_insn_code = 0;
   next_index = 0;
@@ -2182,6 +2537,7 @@ main (argc, argv)
       if (c == EOF)
        break;
       ungetc (c, infile);
+      pattern_lineno = read_rtx_lineno;
 
       desc = read_rtx (infile);
       if (GET_CODE (desc) == DEFINE_INSN)
@@ -2206,6 +2562,9 @@ main (argc, argv)
       next_index++;
     }
 
+  if (error_count)
+    return FATAL_EXIT_CODE;
+
   puts ("\n\n");
 
   process_tree (&recog_tree, RECOG);
@@ -2380,7 +2739,9 @@ debug_decision_1 (d, indent)
          debug_decision_2 (test);
        }
     }
-  fprintf (stderr, "} %d\n", d->number);
+  fprintf (stderr, "} %d n %d a %d\n", d->number,
+          (d->next ? d->next->number : -1),
+          (d->afterward ? d->afterward->number : -1));
 }
 
 static void