OSDN Git Service

* fr.po: Update.
[pf3gnuchains/gcc-fork.git] / gcc / genrecog.c
index 7213ce7..7bdc526 100644 (file)
@@ -1,23 +1,23 @@
 /* Generate code from machine description to recognize rtl as insns.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
-   This file is part of GNU CC.
+   This file is part of GCC.
 
-   GNU CC is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
-   GNU CC is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GNU CC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 
 /* This program is used to produce insn-recog.c, which contains a
 
    This program also generates the function `split_insns', which
    returns 0 if the rtl could not be split, or it returns the split
-   rtl in a SEQUENCE.
+   rtl as an INSN list.
 
    This program also generates the function `peephole2_insns', which
    returns 0 if the rtl could not be matched.  If there was a match,
-   the new rtl is returned in a SEQUENCE, and LAST_INSN will point
+   the new rtl is returned in an INSN list, and LAST_INSN will point
    to the last recognized insn in the old sequence.  */
 
-#include "hconfig.h"
+#include "bconfig.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "errors.h"
 #include "gensupport.h"
@@ -65,7 +67,7 @@ static char **insn_name_ptr = 0;
 static int insn_name_ptr_size = 0;
 
 /* A listhead of decision trees.  The alternatives to a node are kept
-   in a doublely-linked list so we can easily add nodes to the proper
+   in a doubly-linked list so we can easily add nodes to the proper
    place when merging.  */
 
 struct decision_head
@@ -73,7 +75,7 @@ struct decision_head
   struct decision *first;
   struct decision *last;
 };
-    
+
 /* A single test.  The two accept types aren't tests per-se, but
    their equality (or lack thereof) does affect tree merging so
    it is convenient to keep them here.  */
@@ -84,12 +86,14 @@ struct decision_test
   struct decision_test *next;
 
   /* These types are roughly in the order in which we'd like to test them.  */
-  enum decision_type {
-    DT_mode, DT_code, DT_veclen,
-    DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide,
-    DT_dup, DT_pred, DT_c_test, 
-    DT_accept_op, DT_accept_insn
-  } type;
+  enum decision_type
+    {
+      DT_mode, DT_code, DT_veclen,
+      DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide, DT_elt_zero_wide_safe,
+      DT_const_int,
+      DT_veclen_ge, DT_dup, DT_pred, DT_c_test,
+      DT_accept_op, DT_accept_insn
+    } type;
 
   union
   {
@@ -180,42 +184,41 @@ static int error_count;
    of tree nodes.  Also, if a predicate can match only one code, we can
    hardwire that code into the node testing the predicate.  */
 
-static struct pred_table
+static const struct pred_table
 {
-  const char *name;
-  RTX_CODE codes[NUM_RTX_CODE];
+  const char *const name;
+  const RTX_CODE codes[NUM_RTX_CODE];
 } preds[] = {
   {"general_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
-                      LABEL_REF, SUBREG, REG, MEM}},
+                      LABEL_REF, SUBREG, REG, MEM, ADDRESSOF}},
 #ifdef PREDICATE_CODES
   PREDICATE_CODES
 #endif
   {"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}},
+                      LABEL_REF, SUBREG, REG, MEM, ADDRESSOF,
+                      PLUS, MINUS, MULT}},
+  {"register_operand", {SUBREG, REG, ADDRESSOF}},
+  {"pmode_register_operand", {SUBREG, REG, ADDRESSOF}},
   {"scratch_operand", {SCRATCH, REG}},
   {"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
                         LABEL_REF}},
   {"const_int_operand", {CONST_INT}},
   {"const_double_operand", {CONST_INT, CONST_DOUBLE}},
-  {"nonimmediate_operand", {SUBREG, REG, MEM}},
+  {"nonimmediate_operand", {SUBREG, REG, MEM, ADDRESSOF}},
   {"nonmemory_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
-                        LABEL_REF, SUBREG, REG}},
+                        LABEL_REF, SUBREG, REG, ADDRESSOF}},
   {"push_operand", {MEM}},
   {"pop_operand", {MEM}},
   {"memory_operand", {SUBREG, MEM}},
   {"indirect_operand", {SUBREG, MEM}},
   {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU,
                           UNORDERED, ORDERED, UNEQ, UNGE, UNGT, UNLE,
-                          UNLT, LTGT}},
-  {"mode_independent_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
-                               LABEL_REF, SUBREG, REG, MEM}}
+                          UNLT, LTGT}}
 };
 
 #define NUM_KNOWN_PREDS ARRAY_SIZE (preds)
 
-static const char * special_mode_pred_table[] = {
+static const char *const special_mode_pred_table[] = {
 #ifdef SPECIAL_MODE_PREDICATES
   SPECIAL_MODE_PREDICATES
 #endif
@@ -225,99 +228,97 @@ static const char * special_mode_pred_table[] = {
 #define NUM_SPECIAL_MODE_PREDS ARRAY_SIZE (special_mode_pred_table)
 
 static struct decision *new_decision
-  PARAMS ((const char *, struct decision_head *));
+  (const char *, struct decision_head *);
 static struct decision_test *new_decision_test
-  PARAMS ((enum decision_type, struct decision_test ***));
+  (enum decision_type, struct decision_test ***);
 static rtx find_operand
-  PARAMS ((rtx, int));
+  (rtx, int, rtx);
+static rtx find_matching_operand
+  (rtx, int);
 static void validate_pattern
-  PARAMS ((rtx, rtx, rtx, int));
+  (rtx, rtx, rtx, int);
 static struct decision *add_to_sequence
-  PARAMS ((rtx, struct decision_head *, const char *, enum routine_type, int));
+  (rtx, struct decision_head *, const char *, enum routine_type, int);
 
 static int maybe_both_true_2
-  PARAMS ((struct decision_test *, struct decision_test *));
+  (struct decision_test *, struct decision_test *);
 static int maybe_both_true_1
-  PARAMS ((struct decision_test *, struct decision_test *));
+  (struct decision_test *, struct decision_test *);
 static int maybe_both_true
-  PARAMS ((struct decision *, struct decision *, int));
+  (struct decision *, struct decision *, int);
 
 static int nodes_identical_1
-  PARAMS ((struct decision_test *, struct decision_test *));
+  (struct decision_test *, struct decision_test *);
 static int nodes_identical
-  PARAMS ((struct decision *, struct decision *));
+  (struct decision *, struct decision *);
 static void merge_accept_insn
-  PARAMS ((struct decision *, struct decision *));
+  (struct decision *, struct decision *);
 static void merge_trees
-  PARAMS ((struct decision_head *, struct decision_head *));
+  (struct decision_head *, struct decision_head *);
 
 static void factor_tests
-  PARAMS ((struct decision_head *));
+  (struct decision_head *);
 static void simplify_tests
-  PARAMS ((struct decision_head *));
+  (struct decision_head *);
 static int break_out_subroutines
-  PARAMS ((struct decision_head *, int));
+  (struct decision_head *, int);
 static void find_afterward
-  PARAMS ((struct decision_head *, struct decision *));
+  (struct decision_head *, struct decision *);
 
 static void change_state
-  PARAMS ((const char *, const char *, struct decision *, const char *));
+  (const char *, const char *, struct decision *, const char *);
 static void print_code
-  PARAMS ((enum rtx_code));
+  (enum rtx_code);
 static void write_afterward
-  PARAMS ((struct decision *, struct decision *, const char *));
+  (struct decision *, struct decision *, const char *);
 static struct decision *write_switch
-  PARAMS ((struct decision *, int));
+  (struct decision *, int);
 static void write_cond
-  PARAMS ((struct decision_test *, int, enum routine_type));
+  (struct decision_test *, int, enum routine_type);
 static void write_action
-  PARAMS ((struct decision *, struct decision_test *, int, int,
-          struct decision *, enum routine_type));
+  (struct decision *, struct decision_test *, int, int,
+   struct decision *, enum routine_type);
 static int is_unconditional
-  PARAMS ((struct decision_test *, enum routine_type));
+  (struct decision_test *, enum routine_type);
 static int write_node
-  PARAMS ((struct decision *, int, enum routine_type));
+  (struct decision *, int, enum routine_type);
 static void write_tree_1
-  PARAMS ((struct decision_head *, int, enum routine_type));
+  (struct decision_head *, int, enum routine_type);
 static void write_tree
-  PARAMS ((struct decision_head *, const char *, enum routine_type, int));
+  (struct decision_head *, const char *, enum routine_type, int);
 static void write_subroutine
-  PARAMS ((struct decision_head *, enum routine_type));
+  (struct decision_head *, enum routine_type);
 static void write_subroutines
-  PARAMS ((struct decision_head *, enum routine_type));
+  (struct decision_head *, enum routine_type);
 static void write_header
-  PARAMS ((void));
+  (void);
 
 static struct decision_head make_insn_sequence
-  PARAMS ((rtx, enum routine_type));
+  (rtx, enum routine_type);
 static void process_tree
-  PARAMS ((struct decision_head *, enum routine_type));
-  
+  (struct decision_head *, enum routine_type);
+
 static void record_insn_name
-  PARAMS ((int, const char *));
+  (int, const char *);
 
 static void debug_decision_0
-  PARAMS ((struct decision *, int, int));
+  (struct decision *, int, int);
 static void debug_decision_1
-  PARAMS ((struct decision *, int));
+  (struct decision *, int);
 static void debug_decision_2
-  PARAMS ((struct decision_test *));
+  (struct decision_test *);
 extern void debug_decision
-  PARAMS ((struct decision *));
+  (struct decision *);
 extern void debug_decision_list
-  PARAMS ((struct decision *));
+  (struct decision *);
 \f
 /* Create a new node in sequence after LAST.  */
 
 static struct decision *
-new_decision (position, last)
-     const char *position;
-     struct decision_head *last;
+new_decision (const char *position, struct decision_head *last)
 {
-  register struct decision *new
-    = (struct decision *) xmalloc (sizeof (struct decision));
+  struct decision *new = xcalloc (1, sizeof (struct decision));
 
-  memset (new, 0, sizeof (*new));
   new->success = *last;
   new->position = xstrdup (position);
   new->number = next_number++;
@@ -329,14 +330,12 @@ new_decision (position, last)
 /* Create a new test and link it in at PLACE.  */
 
 static struct decision_test *
-new_decision_test (type, pplace)
-     enum decision_type type;
-     struct decision_test ***pplace;
+new_decision_test (enum decision_type type, struct decision_test ***pplace)
 {
   struct decision_test **place = *pplace;
   struct decision_test *test;
 
-  test = (struct decision_test *) xmalloc (sizeof (*test));
+  test = xmalloc (sizeof (*test));
   test->next = *place;
   test->type = type;
   *place = test;
@@ -347,18 +346,19 @@ new_decision_test (type, pplace)
   return test;
 }
 
-/* Search for and return operand N.  */
+/* Search for and return operand N, stop when reaching node STOP.  */
 
 static rtx
-find_operand (pattern, n)
-     rtx pattern;
-     int n;
+find_operand (rtx pattern, int n, rtx stop)
 {
   const char *fmt;
   RTX_CODE code;
   int i, j, len;
   rtx r;
 
+  if (pattern == stop)
+    return stop;
+
   code = GET_CODE (pattern);
   if ((code == MATCH_SCRATCH
        || code == MATCH_INSN
@@ -375,13 +375,70 @@ find_operand (pattern, n)
       switch (fmt[i])
        {
        case 'e': case 'u':
-         if ((r = find_operand (XEXP (pattern, i), n)) != NULL_RTX)
+         if ((r = find_operand (XEXP (pattern, i), n, stop)) != NULL_RTX)
+           return r;
+         break;
+
+       case 'V':
+         if (! XVEC (pattern, i))
+           break;
+         /* Fall through.  */
+
+       case 'E':
+         for (j = 0; j < XVECLEN (pattern, i); j++)
+           if ((r = find_operand (XVECEXP (pattern, i, j), n, stop))
+               != NULL_RTX)
+             return r;
+         break;
+
+       case 'i': case 'w': case '0': case 's':
+         break;
+
+       default:
+         abort ();
+       }
+    }
+
+  return NULL;
+}
+
+/* Search for and return operand M, such that it has a matching
+   constraint for operand N.  */
+
+static rtx
+find_matching_operand (rtx pattern, int n)
+{
+  const char *fmt;
+  RTX_CODE code;
+  int i, j, len;
+  rtx r;
+
+  code = GET_CODE (pattern);
+  if (code == MATCH_OPERAND
+      && (XSTR (pattern, 2)[0] == '0' + n
+         || (XSTR (pattern, 2)[0] == '%'
+             && XSTR (pattern, 2)[1] == '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_matching_operand (XEXP (pattern, i), n)))
            return r;
          break;
 
+       case 'V':
+         if (! XVEC (pattern, i))
+           break;
+         /* Fall through.  */
+
        case 'E':
          for (j = 0; j < XVECLEN (pattern, i); j++)
-           if ((r = find_operand (XVECEXP (pattern, i, j), n)) != NULL_RTX)
+           if ((r = find_matching_operand (XVECEXP (pattern, i, j), n)))
              return r;
          break;
 
@@ -396,16 +453,13 @@ find_operand (pattern, n)
   return NULL;
 }
 
+
 /* 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.  */
 
 static void
-validate_pattern (pattern, insn, set, set_code)
-     rtx pattern;
-     rtx insn;
-     rtx set;
-     int set_code;
+validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
 {
   const char *fmt;
   RTX_CODE code;
@@ -417,7 +471,17 @@ validate_pattern (pattern, insn, set, set_code)
     {
     case MATCH_SCRATCH:
       return;
-
+    case MATCH_DUP:
+    case MATCH_OP_DUP:
+    case MATCH_PAR_DUP:
+      if (find_operand (insn, XINT (pattern, 0), pattern) == pattern)
+       {
+         message_with_line (pattern_lineno,
+                            "operand %i duplicated before defined",
+                            XINT (pattern, 0));
+          error_count++;
+       }
+      break;
     case MATCH_INSN:
     case MATCH_OPERAND:
     case MATCH_OPERATOR:
@@ -458,6 +522,7 @@ validate_pattern (pattern, insn, set, set_code)
                    if (c != REG
                        && c != SUBREG
                        && c != MEM
+                       && c != ADDRESSOF
                        && c != CONCAT
                        && c != PARALLEL
                        && c != STRICT_LOW_PART)
@@ -483,26 +548,51 @@ validate_pattern (pattern, insn, set, set_code)
                }
          }
 
-       /* A MATCH_OPERAND that is a SET should have an output reload.  */
-       if (set && code == MATCH_OPERAND)
+       if (code == MATCH_OPERAND)
          {
-           if (set_code == '+'
-               && XSTR (pattern, 2)[0] != '\0'
-               && XSTR (pattern, 2)[0] != '+')
+           const char constraints0 = XSTR (pattern, 2)[0];
+
+           /* In DEFINE_EXPAND, DEFINE_SPLIT, and DEFINE_PEEPHOLE2, we
+              don't use the MATCH_OPERAND constraint, only the predicate.
+              This is confusing to folks doing new ports, so help them
+              not make the mistake.  */
+           if (GET_CODE (insn) == DEFINE_EXPAND
+               || GET_CODE (insn) == DEFINE_SPLIT
+               || GET_CODE (insn) == DEFINE_PEEPHOLE2)
              {
-               message_with_line (pattern_lineno,
-                                  "operand %d missing in-out reload",
-                                  XINT (pattern, 0));
-               error_count++;
+               if (constraints0)
+                 message_with_line (pattern_lineno,
+                                    "warning: constraints not supported in %s",
+                                    rtx_name[GET_CODE (insn)]);
              }
-           else if (XSTR (pattern, 2)[0] != '\0'
-                    && XSTR (pattern, 2)[0] != '='
-                    && XSTR (pattern, 2)[0] != '+')
+
+           /* A MATCH_OPERAND that is a SET should have an output reload.  */
+           else if (set && constraints0)
              {
-               message_with_line (pattern_lineno,
-                                  "operand %d missing output reload", 
-                                  XINT (pattern, 0));
-               error_count++;
+               if (set_code == '+')
+                 {
+                   if (constraints0 == '+')
+                     ;
+                   /* 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)))
+                     ;
+                   else
+                     {
+                       message_with_line (pattern_lineno,
+                                          "operand %d missing in-out reload",
+                                          XINT (pattern, 0));
+                       error_count++;
+                     }
+                 }
+               else if (constraints0 != '=' && constraints0 != '+')
+                 {
+                   message_with_line (pattern_lineno,
+                                      "operand %d missing output reload",
+                                      XINT (pattern, 0));
+                   error_count++;
+                 }
              }
          }
 
@@ -521,7 +611,7 @@ validate_pattern (pattern, insn, set, set_code)
        /* 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 
+          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.  */
@@ -553,22 +643,22 @@ validate_pattern (pattern, insn, set, set_code)
        dest = SET_DEST (pattern);
        src = SET_SRC (pattern);
 
-       /* Find the referant for a DUP.  */
+       /* 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);
+
+       /* Find the referent 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));
+         dest = find_operand (insn, 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));
-
-       /* 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);
+         src = find_operand (insn, XINT (src, 0), NULL);
 
        dmode = GET_MODE (dest);
        smode = GET_MODE (src);
@@ -589,7 +679,7 @@ validate_pattern (pattern, insn, set, set_code)
            error_count++;
          }
 
-       /* If only one of the operands is VOIDmode, and PC or CC0 is 
+       /* 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
@@ -676,20 +766,16 @@ validate_pattern (pattern, insn, set, set_code)
    A pointer to the final node in the chain is returned.  */
 
 static struct decision *
-add_to_sequence (pattern, last, position, insn_type, top)
-     rtx pattern;
-     struct decision_head *last;
-     const char *position;
-     enum routine_type insn_type;
-     int top;
+add_to_sequence (rtx pattern, struct decision_head *last, const char *position,
+                enum routine_type insn_type, int top)
 {
   RTX_CODE code;
   struct decision *this, *sub;
   struct decision_test *test;
   struct decision_test **place;
   char *subpos;
-  register size_t i;
-  register const char *fmt;
+  size_t i;
+  const char *fmt;
   int depth = strlen (position);
   int len;
   enum machine_mode mode;
@@ -697,7 +783,7 @@ add_to_sequence (pattern, last, position, insn_type, top)
   if (depth > max_depth)
     max_depth = depth;
 
-  subpos = (char *) alloca (depth + 2);
+  subpos = xmalloc (depth + 2);
   strcpy (subpos, position);
   subpos[depth + 1] = 0;
 
@@ -711,7 +797,7 @@ add_to_sequence (pattern, last, position, insn_type, top)
   switch (code)
     {
     case PARALLEL:
-      /* Toplevel peephole pattern. */
+      /* Toplevel peephole pattern.  */
       if (insn_type == PEEPHOLE2 && top)
        {
          /* We don't need the node we just created -- unlink it.  */
@@ -720,23 +806,32 @@ add_to_sequence (pattern, last, position, insn_type, top)
          for (i = 0; i < (size_t) XVECLEN (pattern, 0); i++)
            {
              /* Which insn we're looking at is represented by A-Z. We don't
-                ever use 'A', however; it is always implied. */
+                ever use 'A', however; it is always implied.  */
 
              subpos[depth] = (i > 0 ? 'A' + i : 0);
              sub = add_to_sequence (XVECEXP (pattern, 0, i),
                                     last, subpos, insn_type, 0);
              last = &sub->success;
            }
-         return sub;
+         goto ret;
        }
 
       /* Else nothing special.  */
       break;
 
+    case MATCH_PARALLEL:
+      /* The explicit patterns within a match_parallel enforce a minimum
+        length on the vector.  The match_parallel predicate may allow
+        for more elements.  We do need to check for this minimum here
+        or the code generated to match the internals may reference data
+        beyond the end of the vector.  */
+      test = new_decision_test (DT_veclen_ge, &place);
+      test->u.veclen = XVECLEN (pattern, 2);
+      /* Fall through.  */
+
     case MATCH_OPERAND:
     case MATCH_SCRATCH:
     case MATCH_OPERATOR:
-    case MATCH_PARALLEL:
     case MATCH_INSN:
       {
        const char *pred_name;
@@ -757,30 +852,22 @@ add_to_sequence (pattern, last, position, insn_type, top)
              code = UNKNOWN;
          }
 
-       /* We know exactly what const_int_operand matches -- any CONST_INT.  */
-       if (strcmp ("const_int_operand", pred_name) == 0)
-         {
-           code = CONST_INT;
-           mode = VOIDmode;
-         }
-       else if (pred_name[0] != 0)
+       if (pred_name[0] != 0)
          {
            test = new_decision_test (DT_pred, &place);
            test->u.pred.name = pred_name;
            test->u.pred.mode = mode;
 
-           /* See if we know about this predicate and save its number.  If
-              we do, and it only accepts one code, note that fact.  The
-              predicate `const_int_operand' only tests for a CONST_INT, so
-              if we do so we can avoid calling it at all.
+           /* See if we know about this predicate and save its number.
+              If we do, and it only accepts one code, note that fact.
 
-              Finally, if we know that the predicate does not allow
-              CONST_INT, we know that the only way the predicate can match
-              is if the modes match (here we use the kludge of relying on
-              the fact that "address_operand" accepts CONST_INT; otherwise,
-              it would have to be a special case), so we can test the mode
-              (but we need not).  This fact should considerably simplify the
-              generated code.  */
+              If we know that the predicate does not allow CONST_INT,
+              we know that the only way the predicate can match is if
+              the modes match (here we use the kludge of relying on the
+              fact that "address_operand" accepts CONST_INT; otherwise,
+              it would have to be a special case), so we can test the
+              mode (but we need not).  This fact should considerably
+              simplify the generated code.  */
 
            for (i = 0; i < NUM_KNOWN_PREDS; i++)
              if (! strcmp (preds[i].name, pred_name))
@@ -884,10 +971,16 @@ add_to_sequence (pattern, last, position, insn_type, top)
        }
       else if (fmt[i] == 'w')
        {
+         /* If this value actually fits in an int, we can use a switch
+            statement here, so indicate that.  */
+         enum decision_type type
+           = ((int) XWINT (pattern, i) == XWINT (pattern, i))
+             ? DT_elt_zero_wide_safe : DT_elt_zero_wide;
+
          if (i != 0)
            abort ();
 
-         test = new_decision_test (DT_elt_zero_wide, &place);
+         test = new_decision_test (type, &place);
          test->u.intval = XWINT (pattern, i);
        }
       else if (fmt[i] == 'E')
@@ -913,7 +1006,7 @@ add_to_sequence (pattern, last, position, insn_type, top)
 
        case 'E':
          {
-           register int j;
+           int j;
            for (j = 0; j < XVECLEN (pattern, i); j++)
              {
                subpos[depth] = 'a' + j;
@@ -955,6 +1048,8 @@ add_to_sequence (pattern, last, position, insn_type, top)
   if (this->tests == NULL)
     abort ();
 
+ ret:
+  free (subpos);
   return sub;
 }
 \f
@@ -962,8 +1057,7 @@ add_to_sequence (pattern, last, position, insn_type, top)
    Returns > 0 for "definitely both true" and < 0 for "maybe both true".  */
 
 static int
-maybe_both_true_2 (d1, d2)
-     struct decision_test *d1, *d2;
+maybe_both_true_2 (struct decision_test *d1, struct decision_test *d2)
 {
   if (d1->type == d2->type)
     {
@@ -981,6 +1075,7 @@ maybe_both_true_2 (d1, d2)
        case DT_elt_zero_int:
        case DT_elt_one_int:
        case DT_elt_zero_wide:
+       case DT_elt_zero_wide_safe:
          return d1->u.intval == d2->u.intval;
 
        default:
@@ -1059,6 +1154,12 @@ maybe_both_true_2 (d1, d2)
        }
     }
 
+  /* Tests vs veclen may be known when strict equality is involved.  */
+  if (d1->type == DT_veclen && d2->type == DT_veclen_ge)
+    return d1->u.veclen >= d2->u.veclen;
+  if (d1->type == DT_veclen_ge && d2->type == DT_veclen)
+    return d2->u.veclen >= d1->u.veclen;
+
   return -1;
 }
 
@@ -1066,13 +1167,12 @@ maybe_both_true_2 (d1, d2)
    Returns > 0 for "definitely both true" and < 0 for "maybe both true".  */
 
 static int
-maybe_both_true_1 (d1, d2)
-     struct decision_test *d1, *d2;
+maybe_both_true_1 (struct decision_test *d1, struct decision_test *d2)
 {
   struct decision_test *t1, *t2;
 
   /* A match_operand with no predicate can match anything.  Recognize
-     this by the existance of a lone DT_accept_op test.  */
+     this by the existence of a lone DT_accept_op test.  */
   if (d1->type == DT_accept_op || d2->type == DT_accept_op)
     return 1;
 
@@ -1097,13 +1197,12 @@ maybe_both_true_1 (d1, d2)
    D1 and D2.  Otherwise, return 1 (it may be that there is an RTL that
    can match both or just that we couldn't prove there wasn't such an RTL).
 
-   TOPLEVEL is non-zero if we are to only look at the top level and not
+   TOPLEVEL is nonzero if we are to only look at the top level and not
    recursively descend.  */
 
 static int
-maybe_both_true (d1, d2, toplevel)
-     struct decision *d1, *d2;
-     int toplevel;
+maybe_both_true (struct decision *d1, struct decision *d2,
+                int toplevel)
 {
   struct decision *p1, *p2;
   int cmp;
@@ -1130,14 +1229,14 @@ maybe_both_true (d1, d2, toplevel)
   if (cmp != 0)
     {
       if (toplevel)
-       abort();
+       abort ();
 
       /* If the d2->position was lexically lower, swap.  */
       if (cmp > 0)
        p1 = d1, d1 = d2, d2 = p1;
 
       if (d1->success.first == 0)
-       return 0;
+       return 1;
       for (p1 = d1->success.first; p1; p1 = p1->next)
        if (maybe_both_true (p1, d2, 0))
          return 1;
@@ -1170,8 +1269,7 @@ maybe_both_true (d1, d2, toplevel)
 /* A subroutine of nodes_identical.  Examine two tests for equivalence.  */
 
 static int
-nodes_identical_1 (d1, d2)
-     struct decision_test *d1, *d2;
+nodes_identical_1 (struct decision_test *d1, struct decision_test *d2)
 {
   switch (d1->type)
     {
@@ -1189,6 +1287,7 @@ nodes_identical_1 (d1, d2)
       return strcmp (d1->u.c_test, d2->u.c_test) == 0;
 
     case DT_veclen:
+    case DT_veclen_ge:
       return d1->u.veclen == d2->u.veclen;
 
     case DT_dup:
@@ -1197,6 +1296,7 @@ nodes_identical_1 (d1, d2)
     case DT_elt_zero_int:
     case DT_elt_one_int:
     case DT_elt_zero_wide:
+    case DT_elt_zero_wide_safe:
       return d1->u.intval == d2->u.intval;
 
     case DT_accept_op:
@@ -1212,12 +1312,11 @@ nodes_identical_1 (d1, d2)
 }
 
 /* True iff the two nodes are identical (on one level only).  Due
-   to the way these lists are constructed, we shouldn't have to 
+   to the way these lists are constructed, we shouldn't have to
    consider different orderings on the tests.  */
 
 static int
-nodes_identical (d1, d2)
-     struct decision *d1, *d2;
+nodes_identical (struct decision *d1, struct decision *d2)
 {
   struct decision_test *t1, *t2;
 
@@ -1234,7 +1333,9 @@ nodes_identical (d1, d2)
     return 0;
 
   /* Check that their subnodes are at the same position, as any one set
-     of sibling decisions must be at the same position.  */
+     of sibling decisions must be at the same position.  Allowing this
+     requires complications to find_afterward and when change_state is
+     invoked.  */
   if (d1->success.first
       && d2->success.first
       && strcmp (d1->success.first->position, d2->success.first->position))
@@ -1246,13 +1347,12 @@ nodes_identical (d1, d2)
 /* A subroutine of merge_trees; given two nodes that have been declared
    identical, cope with two insn accept states.  If they differ in the
    number of clobbers, then the conflict was created by make_insn_sequence
-   and we can drop the with-clobbers version on the floor.  If both 
+   and we can drop the with-clobbers version on the floor.  If both
    nodes have no additional clobbers, we have found an ambiguity in the
    source machine description.  */
 
 static void
-merge_accept_insn (oldd, addd)
-     struct decision *oldd, *addd;
+merge_accept_insn (struct decision *oldd, struct decision *addd)
 {
   struct decision_test *old, *add;
 
@@ -1296,8 +1396,7 @@ merge_accept_insn (oldd, addd)
 /* Merge two decision trees OLDH and ADDH, modifying OLDH destructively.  */
 
 static void
-merge_trees (oldh, addh)
-     struct decision_head *oldh, *addh;
+merge_trees (struct decision_head *oldh, struct decision_head *addh)
 {
   struct decision *next, *add;
 
@@ -1334,7 +1433,7 @@ merge_trees (oldh, addh)
         that tests just the same mode.
 
         If we have no match, place NEW after the closest match we found.  */
-        
+
       for (old = oldh->last; old; old = old->prev)
        {
          if (nodes_identical (old, add))
@@ -1351,7 +1450,7 @@ merge_trees (oldh, addh)
             how expensive/important the test is.  Given that the tests
             are also ordered within the list, examining the first is
             sufficient.  */
-         if (add->tests->type < old->tests->type)
+         if ((int) add->tests->type < (int) old->tests->type)
            insert_before = old;
        }
 
@@ -1376,13 +1475,12 @@ merge_trees (oldh, addh)
     }
 }
 \f
-/* Walk the tree looking for sub-nodes that perform common tests.  
+/* Walk the tree looking for sub-nodes that perform common tests.
    Factor out the common test into a new node.  This enables us
    (depending on the test type) to emit switch statements later.  */
 
 static void
-factor_tests (head)
-     struct decision_head *head;
+factor_tests (struct decision_head *head)
 {
   struct decision *first, *next;
 
@@ -1398,14 +1496,14 @@ factor_tests (head)
       if (next->tests->type != type)
        continue;
 
-      /* Don't want all node types, just those we can turn into 
+      /* Don't want all node types, just those we can turn into
         switch statements.  */
       if (type != DT_mode
          && type != DT_code
          && type != DT_veclen
          && type != DT_elt_zero_int
          && type != DT_elt_one_int
-         && type != DT_elt_zero_wide)
+         && type != DT_elt_zero_wide_safe)
        continue;
 
       /* If we'd been performing more than one test, create a new node
@@ -1416,7 +1514,7 @@ factor_tests (head)
          new->tests = first->tests->next;
          first->tests->next = NULL;
        }
-       
+
       /* Crop the node tree off after our first test.  */
       first->next = NULL;
       old_last = head->last;
@@ -1467,8 +1565,7 @@ factor_tests (head)
    predicates, remove them.  */
 
 static void
-simplify_tests (head)
-     struct decision_head *head;
+simplify_tests (struct decision_head *head)
 {
   struct decision *tree;
 
@@ -1505,9 +1602,7 @@ simplify_tests (head)
    that is generated.  */
 
 static int
-break_out_subroutines (head, initial)
-     struct decision_head *head;
-     int initial;
+break_out_subroutines (struct decision_head *head, int initial)
 {
   int size = 0;
   struct decision *sub;
@@ -1527,13 +1622,11 @@ break_out_subroutines (head, initial)
    when p is true.  */
 
 static void
-find_afterward (head, real_afterward)
-     struct decision_head *head;
-     struct decision *real_afterward;
+find_afterward (struct decision_head *head, struct decision *real_afterward)
 {
   struct decision *p, *q, *afterward;
 
-  /* We can't propogate alternatives across subroutine boundaries. 
+  /* We can't propagate alternatives across subroutine boundaries.
      This is not incorrect, merely a minor optimization loss.  */
 
   p = head->first;
@@ -1546,7 +1639,7 @@ find_afterward (head, real_afterward)
        if (maybe_both_true (p, q, 1))
          break;
 
-      /* If we reached the end of the list without finding one, 
+      /* If we reached the end of the list without finding one,
         use the incoming afterward position.  */
       if (!q)
        q = afterward;
@@ -1570,17 +1663,14 @@ find_afterward (head, real_afterward)
 \f
 /* Assuming that the state of argument is denoted by OLDPOS, take whatever
    actions are necessary to move to NEWPOS.  If we fail to move to the
-   new state, branch to node AFTERWARD if non-zero, otherwise return.
+   new state, branch to node AFTERWARD if nonzero, otherwise return.
 
    Failure to move to the new state can only occur if we are trying to
-   match multiple insns and we try to step past the end of the stream. */
+   match multiple insns and we try to step past the end of the stream.  */
 
 static void
-change_state (oldpos, newpos, afterward, indent)
-     const char *oldpos;
-     const char *newpos;
-     struct decision *afterward;
-     const char *indent;
+change_state (const char *oldpos, const char *newpos,
+             struct decision *afterward, const char *indent)
 {
   int odepth = strlen (oldpos);
   int ndepth = strlen (newpos);
@@ -1593,27 +1683,27 @@ change_state (oldpos, newpos, afterward, indent)
 
   /* Hunt for the last [A-Z] in both strings.  */
   for (old_has_insn = odepth - 1; old_has_insn >= 0; --old_has_insn)
-    if (oldpos[old_has_insn] >= 'A' && oldpos[old_has_insn] <= 'Z')
+    if (ISUPPER (oldpos[old_has_insn]))
       break;
   for (new_has_insn = ndepth - 1; new_has_insn >= 0; --new_has_insn)
-    if (newpos[new_has_insn] >= 'A' && newpos[new_has_insn] <= 'Z')
+    if (ISUPPER (newpos[new_has_insn]))
       break;
 
   /* Go down to desired level.  */
   while (depth < ndepth)
     {
-      /* It's a different insn from the first one. */
-      if (newpos[depth] >= 'A' && newpos[depth] <= 'Z')
+      /* It's a different insn from the first one.  */
+      if (ISUPPER (newpos[depth]))
        {
          /* We can only fail if we're moving down the tree.  */
          if (old_has_insn >= 0 && oldpos[old_has_insn] >= newpos[depth])
            {
-             printf ("%stem = peep2_next_insn (%d);\n", 
+             printf ("%stem = peep2_next_insn (%d);\n",
                      indent, newpos[depth] - 'A');
            }
          else
            {
-             printf ("%stem = peep2_next_insn (%d);\n", 
+             printf ("%stem = peep2_next_insn (%d);\n",
                      indent, newpos[depth] - 'A');
              printf ("%sif (tem == NULL_RTX)\n", indent);
              if (afterward)
@@ -1623,7 +1713,7 @@ change_state (oldpos, newpos, afterward, indent)
            }
          printf ("%sx%d = PATTERN (tem);\n", indent, depth + 1);
        }
-      else if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
+      else if (ISLOWER (newpos[depth]))
        printf ("%sx%d = XVECEXP (x%d, 0, %d);\n",
                indent, depth + 1, depth, newpos[depth] - 'a');
       else
@@ -1637,10 +1727,9 @@ change_state (oldpos, newpos, afterward, indent)
    the name.  */
 
 static void
-print_code (code)
-     enum rtx_code code;
+print_code (enum rtx_code code)
 {
-  register const char *p;
+  const char *p;
   for (p = GET_RTX_NAME (code); *p; p++)
     putchar (TOUPPER (*p));
 }
@@ -1648,10 +1737,8 @@ print_code (code)
 /* Emit code to cross an afterward link -- change state and branch.  */
 
 static void
-write_afterward (start, afterward, indent)
-     struct decision *start;
-     struct decision *afterward;
-     const char *indent;
+write_afterward (struct decision *start, struct decision *afterward,
+                const char *indent)
 {
   if (!afterward || start->subroutine_number > 0)
     printf("%sgoto ret0;\n", indent);
@@ -1662,13 +1749,25 @@ write_afterward (start, afterward, indent)
     }
 }
 
-/* Emit a switch statement, if possible, for an initial sequence of 
+/* Emit a HOST_WIDE_INT as an integer constant expression.  We need to take
+   special care to avoid "decimal constant is so large that it is unsigned"
+   warnings in the resulting code.  */
+
+static void
+print_host_wide_int (HOST_WIDE_INT val)
+{
+  HOST_WIDE_INT min = (unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1);
+  if (val == min)
+    printf ("(" HOST_WIDE_INT_PRINT_DEC_C "-1)", val + 1);
+  else
+    printf (HOST_WIDE_INT_PRINT_DEC_C, val);
+}
+
+/* Emit a switch statement, if possible, for an initial sequence of
    nodes at START.  Return the first node yet untested.  */
 
 static struct decision *
-write_switch (start, depth)
-     struct decision *start;
-     int depth;
+write_switch (struct decision *start, int depth)
 {
   struct decision *p = start;
   enum decision_type type = p->tests->type;
@@ -1680,7 +1779,8 @@ write_switch (start, depth)
   if (!p->next
       || p->tests->next
       || p->next->tests->type != type
-      || p->next->tests->next)
+      || p->next->tests->next
+      || nodes_identical_1 (p->tests, p->next->tests))
     return p;
 
   /* DT_code is special in that we can do interesting things with
@@ -1695,7 +1795,7 @@ write_switch (start, depth)
 
       printf ("  switch (GET_CODE (x%d))\n    {\n", depth);
       code = p->tests->u.code;
-      do 
+      do
        {
          if (p != start && p->need_label && needs_label == NULL)
            needs_label = p;
@@ -1774,9 +1874,18 @@ write_switch (start, depth)
           || type == DT_veclen
           || type == DT_elt_zero_int
           || type == DT_elt_one_int
-          || type == DT_elt_zero_wide)
+          || type == DT_elt_zero_wide_safe)
     {
-      printf ("  switch (");
+      const char *indent = "";
+
+      /* We cast switch parameter to integer, so we must ensure that the value
+        fits.  */
+      if (type == DT_elt_zero_wide_safe)
+       {
+         indent = "  ";
+         printf("  if ((int) XWINT (x%d, 0) == XWINT (x%d, 0))\n", depth, depth);
+       }
+      printf ("%s  switch (", indent);
       switch (type)
        {
        case DT_mode:
@@ -1791,7 +1900,7 @@ write_switch (start, depth)
        case DT_elt_one_int:
          printf ("XINT (x%d, 1)", depth);
          break;
-       case DT_elt_zero_wide:
+       case DT_elt_zero_wide_safe:
          /* 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);
@@ -1799,14 +1908,22 @@ write_switch (start, depth)
        default:
          abort ();
        }
-      printf (")\n    {\n");
+      printf (")\n%s    {\n", indent);
 
       do
        {
+         /* Merge trees will not unify identical nodes if their
+            sub-nodes are at different levels.  Thus we must check
+            for duplicate cases.  */
+         struct decision *q;
+         for (q = start; q != p; q = q->next)
+           if (nodes_identical_1 (p->tests, q->tests))
+             goto case_done;
+
          if (p != start && p->need_label && needs_label == NULL)
            needs_label = p;
 
-         printf ("    case ");
+         printf ("%s    case ", indent);
          switch (type)
            {
            case DT_mode:
@@ -1818,25 +1935,28 @@ write_switch (start, depth)
            case DT_elt_zero_int:
            case DT_elt_one_int:
            case DT_elt_zero_wide:
-             printf (HOST_WIDE_INT_PRINT_DEC, p->tests->u.intval);
+           case DT_elt_zero_wide_safe:
+             print_host_wide_int (p->tests->u.intval);
              break;
            default:
              abort ();
            }
-         printf (":\n      goto L%d;\n", p->success.first->number);
+         printf (":\n%s      goto L%d;\n", indent, p->success.first->number);
          p->success.first->need_label = 1;
 
          p = p->next;
        }
       while (p && p->tests->type == type && !p->tests->next);
-      
-      printf ("    default:\n      break;\n    }\n");
+
+    case_done:
+      printf ("%s    default:\n%s      break;\n%s    }\n",
+             indent, indent, indent);
 
       return needs_label != NULL ? needs_label : p;
     }
   else
     {
-      /* None of the other tests are ameanable.  */
+      /* None of the other tests are amenable.  */
       return p;
     }
 }
@@ -1844,10 +1964,8 @@ write_switch (start, depth)
 /* Emit code for one test.  */
 
 static void
-write_cond (p, depth, subroutine_type)
-     struct decision_test *p;
-     int depth;
-     enum routine_type subroutine_type;
+write_cond (struct decision_test *p, int depth,
+           enum routine_type subroutine_type)
 {
   switch (p->type)
     {
@@ -1873,8 +1991,18 @@ write_cond (p, depth, subroutine_type)
       break;
 
     case DT_elt_zero_wide:
+    case DT_elt_zero_wide_safe:
       printf ("XWINT (x%d, 0) == ", depth);
-      printf (HOST_WIDE_INT_PRINT_DEC, p->u.intval);
+      print_host_wide_int (p->u.intval);
+      break;
+
+    case DT_const_int:
+      printf ("x%d == const_int_rtx[MAX_SAVED_CONST_INT + (%d)]",
+             depth, (int) p->u.intval);
+      break;
+
+    case DT_veclen_ge:
+      printf ("XVECLEN (x%d, 0) >= %d", depth, p->u.veclen);
       break;
 
     case DT_dup:
@@ -1914,12 +2042,9 @@ write_cond (p, depth, subroutine_type)
    perform a state change.  For the `accept' tests we must do more work.  */
 
 static void
-write_action (p, test, depth, uncond, success, subroutine_type)
-     struct decision *p;
-     struct decision_test *test;
-     int depth, uncond;
-     struct decision *success;
-     enum routine_type subroutine_type;
+write_action (struct decision *p, struct decision_test *test,
+             int depth, int uncond, struct decision *success,
+             enum routine_type subroutine_type)
 {
   const char *indent;
   int want_close = 0;
@@ -1973,7 +2098,7 @@ write_action (p, test, depth, uncond, success, subroutine_type)
            int match_len = 0, i;
 
            for (i = strlen (p->position) - 1; i >= 0; --i)
-             if (p->position[i] >= 'A' && p->position[i] <= 'Z')
+             if (ISUPPER (p->position[i]))
                {
                  match_len = p->position[i] - 'A';
                  break;
@@ -2005,9 +2130,7 @@ write_action (p, test, depth, uncond, success, subroutine_type)
 /* ??? is_unconditional is a stupid name for a tri-state function.  */
 
 static int
-is_unconditional (t, subroutine_type)
-     struct decision_test *t;
-     enum routine_type subroutine_type;
+is_unconditional (struct decision_test *t, enum routine_type subroutine_type)
 {
   if (t->type == DT_accept_op)
     return 1;
@@ -2034,14 +2157,29 @@ is_unconditional (t, subroutine_type)
    Return true if there is no fallthru path.  */
 
 static int
-write_node (p, depth, subroutine_type)
-     struct decision *p;
-     int depth;
-     enum routine_type subroutine_type;
+write_node (struct decision *p, int depth,
+           enum routine_type subroutine_type)
 {
   struct decision_test *test, *last_test;
   int uncond;
 
+  /* Scan the tests and simplify comparisons against small
+     constants.  */
+  for (test = p->tests; test; test = test->next)
+    {
+      if (test->type == DT_code
+         && test->u.code == CONST_INT
+         && test->next
+         && test->next->type == DT_elt_zero_wide_safe
+         && -MAX_SAVED_CONST_INT <= test->next->u.intval
+         && test->next->u.intval <= MAX_SAVED_CONST_INT)
+       {
+         test->type = DT_const_int;
+         test->u.intval = test->next->u.intval;
+         test->next = test->next->next;
+       }
+    }
+
   last_test = test = p->tests;
   uncond = is_unconditional (test, subroutine_type);
   if (uncond == 0)
@@ -2051,11 +2189,8 @@ write_node (p, depth, subroutine_type)
 
       while ((test = test->next) != NULL)
        {
-         int uncond2;
-
          last_test = test;
-         uncond2 = is_unconditional (test, subroutine_type);
-         if (uncond2 != 0)
+         if (is_unconditional (test, subroutine_type))
            break;
 
          printf ("\n      && ");
@@ -2073,10 +2208,8 @@ write_node (p, depth, subroutine_type)
 /* Emit code for all of the sibling nodes of HEAD.  */
 
 static void
-write_tree_1 (head, depth, subroutine_type)
-     struct decision_head *head;
-     int depth;
-     enum routine_type subroutine_type;
+write_tree_1 (struct decision_head *head, int depth,
+             enum routine_type subroutine_type)
 {
   struct decision *p, *next;
   int uncond = 0;
@@ -2109,13 +2242,10 @@ write_tree_1 (head, depth, subroutine_type)
    position at the node that branched to this node.  */
 
 static void
-write_tree (head, prevpos, type, initial)
-     struct decision_head *head;
-     const char *prevpos;
-     enum routine_type type;
-     int initial;
+write_tree (struct decision_head *head, const char *prevpos,
+           enum routine_type type, int initial)
 {
-  register struct decision *p = head->first;
+  struct decision *p = head->first;
 
   putchar ('\n');
   if (p->need_label)
@@ -2169,15 +2299,13 @@ write_tree (head, prevpos, type, initial)
    node TREE.  */
 
 static void
-write_subroutine (head, type)
-     struct decision_head *head;
-     enum routine_type type;
+write_subroutine (struct decision_head *head, enum routine_type type)
 {
   int subfunction = head->first ? head->first->subroutine_number : 0;
   const char *s_or_e;
   char extension[32];
   int i;
-  
+
   s_or_e = subfunction ? "static " : "";
 
   if (subfunction)
@@ -2190,34 +2318,24 @@ write_subroutine (head, type)
   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);
+recog%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *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);
+split%s (rtx x0 ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)\n",
+             s_or_e, extension);
       break;
     case PEEPHOLE2:
-      printf ("%srtx peephole2%s PARAMS ((rtx, rtx, int *));\n",
-             s_or_e, extension);
       printf ("%srtx\n\
-peephole2%s (x0, insn, _pmatch_len)\n\
-     register rtx x0;\n\
-     rtx insn ATTRIBUTE_UNUSED;\n\
-     int *_pmatch_len ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+peephole2%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *_pmatch_len ATTRIBUTE_UNUSED)\n",
+             s_or_e, extension);
       break;
     }
 
-  printf ("{\n  register rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];\n");
+  printf ("{\n  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);
+    printf ("  rtx x%d ATTRIBUTE_UNUSED;\n", i);
 
   printf ("  %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int");
 
@@ -2236,9 +2354,7 @@ peephole2%s (x0, insn, _pmatch_len)\n\
    subroutines, but did not write them out.  Do so now.  */
 
 static void
-write_subroutines (head, type)
-     struct decision_head *head;
-     enum routine_type type;
+write_subroutines (struct decision_head *head, enum routine_type type)
 {
   struct decision *p;
 
@@ -2253,7 +2369,7 @@ write_subroutines (head, type)
 /* Begin the output file.  */
 
 static void
-write_header ()
+write_header (void)
 {
   puts ("\
 /* Generated automatically by the program `genrecog' from the target\n\
@@ -2261,6 +2377,8 @@ write_header ()
 \n\
 #include \"config.h\"\n\
 #include \"system.h\"\n\
+#include \"coretypes.h\"\n\
+#include \"tm.h\"\n\
 #include \"rtl.h\"\n\
 #include \"tm_p.h\"\n\
 #include \"function.h\"\n\
@@ -2271,6 +2389,8 @@ write_header ()
 #include \"flags.h\"\n\
 #include \"hard-reg-set.h\"\n\
 #include \"resource.h\"\n\
+#include \"toplev.h\"\n\
+#include \"reload.h\"\n\
 \n");
 
   puts ("\n\
@@ -2296,10 +2416,10 @@ write_header ()
 
   puts ("\n\
    The function split_insns returns 0 if the rtl could not\n\
-   be split or the split rtl in a SEQUENCE if it can be.\n\
+   be split or the split rtl as an INSN list if it can be.\n\
 \n\
    The function peephole2_insns returns 0 if the rtl could not\n\
-   be matched. If there was a match, the new rtl is returned in a SEQUENCE,\n\
+   be matched. If there was a match, the new rtl is returned in an INSN list,\n\
    and LAST_INSN will point to the last recognized insn in the old sequence.\n\
 */\n\n");
 }
@@ -2311,17 +2431,20 @@ write_header ()
    TYPE says what type of routine we are recognizing (RECOG or SPLIT).  */
 
 static struct decision_head
-make_insn_sequence (insn, type)
-     rtx insn;
-     enum routine_type type;
+make_insn_sequence (rtx insn, enum routine_type type)
 {
   rtx x;
   const char *c_test = XSTR (insn, type == RECOG ? 2 : 1);
+  int truth = maybe_eval_c_test (c_test);
   struct decision *last;
   struct decision_test *test, **place;
   struct decision_head head;
   char c_test_pos[2];
 
+  /* We should never see an insn whose C test is false at compile time.  */
+  if (truth == 0)
+    abort ();
+
   record_insn_name (next_insn_code, (type == RECOG ? XSTR (insn, 0) : NULL));
 
   c_test_pos[0] = '\0';
@@ -2369,7 +2492,8 @@ make_insn_sequence (insn, type)
     continue;
   place = &test->next;
 
-  if (c_test[0])
+  /* Skip the C test if it's known to be true at compile time.  */
+  if (truth == -1)
     {
       /* Need a new node if we have another test to add.  */
       if (test->type == DT_accept_op)
@@ -2389,7 +2513,7 @@ make_insn_sequence (insn, type)
   switch (type)
     {
     case RECOG:
-      /* If this is an DEFINE_INSN and X is a PARALLEL, see if it ends
+      /* If this is a DEFINE_INSN and X is a PARALLEL, see if it ends
         with a group of CLOBBERs of (hard) registers or MATCH_SCRATCHes.
         If so, set up to recognize the pattern without these CLOBBERs.  */
 
@@ -2442,7 +2566,9 @@ make_insn_sequence (insn, type)
                  place = &last->tests;
                }
 
-             if (c_test[0])
+             /* Skip the C test if it's known to be true at compile
+                 time.  */
+             if (truth == -1)
                {
                  test = new_decision_test (DT_c_test, &place);
                  test->u.c_test = c_test;
@@ -2460,12 +2586,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 PARAMS ((rtx *));\n", next_insn_code);
+      printf ("extern rtx gen_split_%d (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 PARAMS ((rtx, rtx *));\n",
+      printf ("extern rtx gen_peephole2_%d (rtx, rtx *);\n",
              next_insn_code);
       break;
     }
@@ -2474,9 +2600,7 @@ make_insn_sequence (insn, type)
 }
 
 static void
-process_tree (head, subroutine_type)
-     struct decision_head *head;
-     enum routine_type subroutine_type;
+process_tree (struct decision_head *head, enum routine_type subroutine_type)
 {
   if (head->first == NULL)
     {
@@ -2503,12 +2627,10 @@ process_tree (head, subroutine_type)
   write_subroutine (head, subroutine_type);
 }
 \f
-extern int main PARAMS ((int, char **));
+extern int main (int, char **);
 
 int
-main (argc, argv)
-     int argc;
-     char **argv;
+main (int argc, char **argv)
 {
   rtx desc;
   struct decision_head recog_tree, split_tree, peephole2_tree, h;
@@ -2520,9 +2642,9 @@ main (argc, argv)
   memset (&peephole2_tree, 0, sizeof peephole2_tree);
 
   if (argc <= 1)
-    fatal ("No input file name.");
+    fatal ("no input file name");
 
-  if (init_md_reader (argv[1]) != SUCCESS_EXIT_CODE)
+  if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
     return (FATAL_EXIT_CODE);
 
   next_insn_code = 0;
@@ -2553,7 +2675,7 @@ main (argc, argv)
          h = make_insn_sequence (desc, PEEPHOLE2);
          merge_trees (&peephole2_tree, &h);
        }
-       
+
       next_index++;
     }
 
@@ -2572,8 +2694,7 @@ main (argc, argv)
 \f
 /* Define this so we can link with print-rtl.o to get debug_rtx function.  */
 const char *
-get_insn_name (code)
-     int code;
+get_insn_name (int code)
 {
   if (code < insn_name_ptr_size)
     return insn_name_ptr[code];
@@ -2582,9 +2703,7 @@ get_insn_name (code)
 }
 
 static void
-record_insn_name (code, name)
-     int code;
-     const char *name;
+record_insn_name (int code, const char *name)
 {
   static const char *last_real_name = "insn";
   static int last_real_code = 0;
@@ -2594,9 +2713,8 @@ record_insn_name (code, name)
     {
       int new_size;
       new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
-      insn_name_ptr =
-       (char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size);
-      memset (insn_name_ptr + insn_name_ptr_size, 0, 
+      insn_name_ptr = xrealloc (insn_name_ptr, sizeof(char *) * new_size);
+      memset (insn_name_ptr + insn_name_ptr_size, 0,
              sizeof(char *) * (new_size - insn_name_ptr_size));
       insn_name_ptr_size = new_size;
     }
@@ -2611,13 +2729,12 @@ record_insn_name (code, name)
       last_real_name = new = xstrdup (name);
       last_real_code = code;
     }
-  
+
   insn_name_ptr[code] = new;
-}  
+}
 \f
 static void
-debug_decision_2 (test)
-     struct decision_test *test;
+debug_decision_2 (struct decision_test *test)
 {
   switch (test->type)
     {
@@ -2637,8 +2754,13 @@ debug_decision_2 (test)
       fprintf (stderr, "elt1_i=%d", (int) test->u.intval);
       break;
     case DT_elt_zero_wide:
-      fprintf (stderr, "elt0_w=");
-      fprintf (stderr, HOST_WIDE_INT_PRINT_DEC, test->u.intval);
+      fprintf (stderr, "elt0_w=" HOST_WIDE_INT_PRINT_DEC, test->u.intval);
+      break;
+    case DT_elt_zero_wide_safe:
+      fprintf (stderr, "elt0_ws=" HOST_WIDE_INT_PRINT_DEC, test->u.intval);
+      break;
+    case DT_veclen_ge:
+      fprintf (stderr, "veclen>=%d", test->u.veclen);
       break;
     case DT_dup:
       fprintf (stderr, "dup=%d", test->u.dup);
@@ -2659,7 +2781,7 @@ debug_decision_2 (test)
       fprintf (stderr, "A_op=%d", test->u.opno);
       break;
     case DT_accept_insn:
-      fprintf (stderr, "A_insn=(%d,%d)", 
+      fprintf (stderr, "A_insn=(%d,%d)",
               test->u.insn.code_number, test->u.insn.num_clobbers_to_add);
       break;
 
@@ -2669,9 +2791,7 @@ debug_decision_2 (test)
 }
 
 static void
-debug_decision_1 (d, indent)
-     struct decision *d;
-     int indent;
+debug_decision_1 (struct decision *d, int indent)
 {
   int i;
   struct decision_test *test;
@@ -2704,9 +2824,7 @@ debug_decision_1 (d, indent)
 }
 
 static void
-debug_decision_0 (d, indent, maxdepth)
-     struct decision *d;
-     int indent, maxdepth;
+debug_decision_0 (struct decision *d, int indent, int maxdepth)
 {
   struct decision *n;
   int i;
@@ -2727,15 +2845,13 @@ debug_decision_0 (d, indent, maxdepth)
 }
 
 void
-debug_decision (d)
-     struct decision *d;
+debug_decision (struct decision *d)
 {
   debug_decision_0 (d, 0, 1000000);
 }
 
 void
-debug_decision_list (d)
-     struct decision *d;
+debug_decision_list (struct decision *d)
 {
   while (d)
     {