OSDN Git Service

* config/m68k/m68k.c (m68k_rtx_costs): Adjust mul/div costs for
[pf3gnuchains/gcc-fork.git] / gcc / recog.c
index 833a122..7e75f34 100644 (file)
@@ -1,27 +1,29 @@
 /* Subroutines used by or related to instruction recognition.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 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
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+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.  */
 
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "insn-config.h"
@@ -29,6 +31,7 @@ Boston, MA 02111-1307, USA.  */
 #include "hard-reg-set.h"
 #include "recog.h"
 #include "regs.h"
+#include "expr.h"
 #include "function.h"
 #include "flags.h"
 #include "real.h"
@@ -53,10 +56,10 @@ Boston, MA 02111-1307, USA.  */
 #endif
 #endif
 
-static void validate_replace_rtx_1     PARAMS ((rtx *, rtx, rtx, rtx));
-static rtx *find_single_use_1          PARAMS ((rtx, rtx *));
-static rtx *find_constant_term_loc     PARAMS ((rtx *));
-static void validate_replace_src_1     PARAMS ((rtx *, void *));
+static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx);
+static rtx *find_single_use_1 (rtx, rtx *);
+static void validate_replace_src_1 (rtx *, void *);
+static rtx split_insn (rtx);
 
 /* Nonzero means allow operands to be volatile.
    This should be 0 if you are generating rtl, such as if you are calling
@@ -85,18 +88,21 @@ int which_alternative;
 
 int reload_completed;
 
+/* Nonzero after thread_prologue_and_epilogue_insns has run.  */
+int epilogue_completed;
+
 /* Initialize data used by the function `recog'.
    This must be called once in the compilation of a function
    before any insn recognition may be done in the function.  */
 
 void
-init_recog_no_volatile ()
+init_recog_no_volatile (void)
 {
   volatile_ok = 0;
 }
 
 void
-init_recog ()
+init_recog (void)
 {
   volatile_ok = 1;
 }
@@ -111,8 +117,7 @@ init_recog ()
    through this one.  (The only exception is in combine.c.)  */
 
 int
-recog_memoized_1 (insn)
-     rtx insn;
+recog_memoized_1 (rtx insn)
 {
   if (INSN_CODE (insn) < 0)
     INSN_CODE (insn) = recog (PATTERN (insn), insn, 0);
@@ -123,8 +128,7 @@ recog_memoized_1 (insn)
    and that the operands mentioned in it are legitimate.  */
 
 int
-check_asm_operands (x)
-     rtx x;
+check_asm_operands (rtx x)
 {
   int noperands;
   rtx *operands;
@@ -146,8 +150,8 @@ check_asm_operands (x)
   if (noperands == 0)
     return 1;
 
-  operands = (rtx *) alloca (noperands * sizeof (rtx));
-  constraints = (const char **) alloca (noperands * sizeof (char *));
+  operands = alloca (noperands * sizeof (rtx));
+  constraints = alloca (noperands * sizeof (char *));
 
   decode_asm_operands (x, operands, NULL, constraints, NULL);
 
@@ -156,11 +160,11 @@ check_asm_operands (x)
       const char *c = constraints[i];
       if (c[0] == '%')
        c++;
-      if (ISDIGIT ((unsigned char)c[0]) && c[1] == '\0')
+      if (ISDIGIT ((unsigned char) c[0]) && c[1] == '\0')
        c = constraints[c[0] - '0'];
 
       if (! asm_operand_ok (operands[i], c))
-        return 0;
+       return 0;
     }
 
   return 1;
@@ -181,7 +185,7 @@ static int changes_allocated;
 
 static int num_changes = 0;
 
-/* Validate a proposed change to OBJECT.  LOC is the location in the rtl for
+/* Validate a proposed change to OBJECT.  LOC is the location in the rtl
    at which NEW will be placed.  If OBJECT is zero, no validation is done,
    the change is simply made.
 
@@ -190,7 +194,7 @@ static int num_changes = 0;
    an INSN, CALL_INSN, or JUMP_INSN, the insn will be re-recognized with
    the change in place.
 
-   IN_GROUP is non-zero if this is part of a group of changes that must be
+   IN_GROUP is nonzero if this is part of a group of changes that must be
    performed as a group.  In that case, the changes will be stored.  The
    function `apply_change_group' will validate and apply the changes.
 
@@ -200,11 +204,7 @@ static int num_changes = 0;
    Otherwise, perform the change and return 1.  */
 
 int
-validate_change (object, loc, new, in_group)
-    rtx object;
-    rtx *loc;
-    rtx new;
-    int in_group;
+validate_change (rtx object, rtx *loc, rtx new, int in_group)
 {
   rtx old = *loc;
 
@@ -214,7 +214,7 @@ validate_change (object, loc, new, in_group)
   if (in_group == 0 && num_changes != 0)
     abort ();
 
-   *loc = new;
+  *loc = new;
 
   /* Save the information describing this change.  */
   if (num_changes >= changes_allocated)
@@ -226,11 +226,9 @@ validate_change (object, loc, new, in_group)
       else
        changes_allocated *= 2;
 
-      changes = 
-       (change_t*) xrealloc (changes, 
-                             sizeof (change_t) * changes_allocated); 
+      changes = xrealloc (changes, sizeof (change_t) * changes_allocated);
     }
-  
+
   changes[num_changes].object = object;
   changes[num_changes].loc = loc;
   changes[num_changes].old = old;
@@ -258,8 +256,7 @@ validate_change (object, loc, new, in_group)
    were valid; i.e. whether INSN can still be recognized.  */
 
 int
-insn_invalid_p (insn)
-     rtx insn;
+insn_invalid_p (rtx insn)
 {
   rtx pat = PATTERN (insn);
   int num_clobbers = 0;
@@ -271,7 +268,7 @@ insn_invalid_p (insn)
                     ? &num_clobbers : 0);
   int is_asm = icode < 0 && asm_noperands (PATTERN (insn)) >= 0;
 
-  
+
   /* If this is an asm and the operand aren't legal, then fail.  Likewise if
      this is not an asm and the insn wasn't recognized.  */
   if ((is_asm && ! check_asm_operands (PATTERN (insn)))
@@ -307,11 +304,18 @@ insn_invalid_p (insn)
   return 0;
 }
 
+/* Return number of changes made and not validated yet.  */
+int
+num_changes_pending (void)
+{
+  return num_changes;
+}
+
 /* Apply a group of changes previously issued with `validate_change'.
    Return 1 if all changes are valid, zero otherwise.  */
 
 int
-apply_change_group ()
+apply_change_group (void)
 {
   int i;
   rtx last_validated = NULL_RTX;
@@ -329,7 +333,7 @@ apply_change_group ()
     {
       rtx object = changes[i].object;
 
-      /* if there is no object to test or if it is the same as the one we
+      /* If there is no object to test or if it is the same as the one we
          already tested, ignore it.  */
       if (object == 0 || object == last_validated)
        continue;
@@ -352,33 +356,33 @@ apply_change_group ()
              && GET_CODE (XVECEXP (pat, 0, XVECLEN (pat, 0) - 1)) == CLOBBER
              && asm_noperands (PATTERN (object)) < 0)
            {
-              rtx newpat;
-
-              if (XVECLEN (pat, 0) == 2)
-                newpat = XVECEXP (pat, 0, 0);
-              else
-                {
-                  int j;
-
-                  newpat
-                    = gen_rtx_PARALLEL (VOIDmode, 
-                                        rtvec_alloc (XVECLEN (pat, 0) - 1));
-                  for (j = 0; j < XVECLEN (newpat, 0); j++)
-                    XVECEXP (newpat, 0, j) = XVECEXP (pat, 0, j);
-                }
-
-              /* Add a new change to this group to replace the pattern
-                 with this new pattern.  Then consider this change
-                 as having succeeded.  The change we added will
-                 cause the entire call to fail if things remain invalid.
-
-                 Note that this can lose if a later change than the one
-                 we are processing specified &XVECEXP (PATTERN (object), 0, X)
-                 but this shouldn't occur.  */
-
-              validate_change (object, &PATTERN (object), newpat, 1);
-              continue;
-            }
+             rtx newpat;
+
+             if (XVECLEN (pat, 0) == 2)
+               newpat = XVECEXP (pat, 0, 0);
+             else
+               {
+                 int j;
+
+                 newpat
+                   = gen_rtx_PARALLEL (VOIDmode,
+                                       rtvec_alloc (XVECLEN (pat, 0) - 1));
+                 for (j = 0; j < XVECLEN (newpat, 0); j++)
+                   XVECEXP (newpat, 0, j) = XVECEXP (pat, 0, j);
+               }
+
+             /* Add a new change to this group to replace the pattern
+                with this new pattern.  Then consider this change
+                as having succeeded.  The change we added will
+                cause the entire call to fail if things remain invalid.
+
+                Note that this can lose if a later change than the one
+                we are processing specified &XVECEXP (PATTERN (object), 0, X)
+                but this shouldn't occur.  */
+
+             validate_change (object, &PATTERN (object), newpat, 1);
+             continue;
+           }
          else if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
            /* If this insn is a CLOBBER or USE, it is always valid, but is
               never recognized.  */
@@ -391,6 +395,14 @@ apply_change_group ()
 
   if (i == num_changes)
     {
+      basic_block bb;
+
+      for (i = 0; i < num_changes; i++)
+       if (changes[i].object
+           && INSN_P (changes[i].object)
+           && (bb = BLOCK_FOR_INSN (changes[i].object)))
+         bb->flags |= BB_DIRTY;
+
       num_changes = 0;
       return 1;
     }
@@ -401,10 +413,10 @@ apply_change_group ()
     }
 }
 
-/* Return the number of changes so far in the current group.   */
+/* Return the number of changes so far in the current group.  */
 
 int
-num_validated_changes ()
+num_validated_changes (void)
 {
   return num_changes;
 }
@@ -412,8 +424,7 @@ num_validated_changes ()
 /* Retract the changes numbered NUM and up.  */
 
 void
-cancel_changes (num)
-     int num;
+cancel_changes (int num)
 {
   int i;
 
@@ -432,13 +443,11 @@ cancel_changes (num)
    validate_change passing OBJECT.  */
 
 static void
-validate_replace_rtx_1 (loc, from, to, object)
-     rtx *loc;
-     rtx from, to, object;
+validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object)
 {
-  register int i, j;
-  register const char *fmt;
-  register rtx x = *loc;
+  int i, j;
+  const char *fmt;
+  rtx x = *loc;
   enum rtx_code code;
   enum machine_mode op0_mode = VOIDmode;
   int prev_changes = num_changes;
@@ -467,7 +476,7 @@ validate_replace_rtx_1 (loc, from, to, object)
       return;
     }
 
-  /* Call ourseves recursivly to perform the replacements.  */
+  /* Call ourself recursively to perform the replacements.  */
 
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
@@ -478,7 +487,7 @@ validate_replace_rtx_1 (loc, from, to, object)
          validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object);
     }
 
-  /* In case we didn't substituted, there is nothing to do.  */
+  /* If we didn't substitute, there is nothing more to do.  */
   if (num_changes == prev_changes)
     return;
 
@@ -506,12 +515,13 @@ validate_replace_rtx_1 (loc, from, to, object)
     {
     case PLUS:
       /* If we have a PLUS whose second operand is now a CONST_INT, use
-         plus_constant to try to simplify it.
+         simplify_gen_binary to try to simplify it.
          ??? We may want later to remove this, once simplification is
          separated from this function.  */
       if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)
        validate_change (object, loc,
-                        plus_constant (XEXP (x, 0), INTVAL (to)), 1);
+                        simplify_gen_binary
+                        (PLUS, GET_MODE (x), XEXP (x, 0), XEXP (x, 1)), 1);
       break;
     case MINUS:
       if (GET_CODE (XEXP (x, 1)) == CONST_INT
@@ -520,8 +530,8 @@ validate_replace_rtx_1 (loc, from, to, object)
                         simplify_gen_binary
                         (PLUS, GET_MODE (x), XEXP (x, 0),
                          simplify_gen_unary (NEG,
-                                             op0_mode, XEXP (x, 1),
-                                             op0_mode)), 1);
+                                             GET_MODE (x), XEXP (x, 1),
+                                             GET_MODE (x))), 1);
       break;
     case ZERO_EXTEND:
     case SIGN_EXTEND:
@@ -541,7 +551,7 @@ validate_replace_rtx_1 (loc, from, to, object)
       new = simplify_subreg (GET_MODE (x), SUBREG_REG (x), op0_mode,
                             SUBREG_BYTE (x));
 
-      /* Subregs of VOIDmode operands are incorect.  */
+      /* Subregs of VOIDmode operands are incorrect.  */
       if (!new && GET_MODE (SUBREG_REG (x)) == VOIDmode)
        new = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
       if (new)
@@ -564,22 +574,20 @@ validate_replace_rtx_1 (loc, from, to, object)
          enum machine_mode is_mode = GET_MODE (XEXP (x, 0));
          int pos = INTVAL (XEXP (x, 2));
 
-#ifdef HAVE_extzv
-         if (code == ZERO_EXTRACT)
+         if (GET_CODE (x) == ZERO_EXTRACT)
            {
-             wanted_mode = insn_data[(int) CODE_FOR_extzv].operand[1].mode;
-             if (wanted_mode == VOIDmode)
-               wanted_mode = word_mode;
+             enum machine_mode new_mode
+               = mode_for_extraction (EP_extzv, 1);
+             if (new_mode != MAX_MACHINE_MODE)
+               wanted_mode = new_mode;
            }
-#endif
-#ifdef HAVE_extv
-         if (code == SIGN_EXTRACT)
+         else if (GET_CODE (x) == SIGN_EXTRACT)
            {
-             wanted_mode = insn_data[(int) CODE_FOR_extv].operand[1].mode;
-             if (wanted_mode == VOIDmode)
-               wanted_mode = word_mode;
+             enum machine_mode new_mode
+               = mode_for_extraction (EP_extv, 1);
+             if (new_mode != MAX_MACHINE_MODE)
+               wanted_mode = new_mode;
            }
-#endif
 
          /* If we have a narrower mode, we can do something.  */
          if (wanted_mode != VOIDmode
@@ -597,10 +605,7 @@ validate_replace_rtx_1 (loc, from, to, object)
 
              pos %= GET_MODE_BITSIZE (wanted_mode);
 
-             newmem = gen_rtx_MEM (wanted_mode,
-                                   plus_constant (XEXP (XEXP (x, 0), 0),
-                                                  offset));
-             MEM_COPY_ATTRIBUTES (newmem, XEXP (x, 0));
+             newmem = adjust_address_nv (XEXP (x, 0), wanted_mode, offset);
 
              validate_change (object, &XEXP (x, 2), GEN_INT (pos), 1);
              validate_change (object, &XEXP (x, 0), newmem, 1);
@@ -619,8 +624,7 @@ validate_replace_rtx_1 (loc, from, to, object)
    if INSN is still valid.  */
 
 int
-validate_replace_rtx_subexp (from, to, insn, loc)
-     rtx from, to, insn, *loc;
+validate_replace_rtx_subexp (rtx from, rtx to, rtx insn, rtx *loc)
 {
   validate_replace_rtx_1 (loc, from, to, insn);
   return apply_change_group ();
@@ -630,8 +634,7 @@ validate_replace_rtx_subexp (from, to, insn, loc)
    changes have been made, validate by seeing if INSN is still valid.  */
 
 int
-validate_replace_rtx (from, to, insn)
-     rtx from, to, insn;
+validate_replace_rtx (rtx from, rtx to, rtx insn)
 {
   validate_replace_rtx_1 (&PATTERN (insn), from, to, insn);
   return apply_change_group ();
@@ -640,8 +643,7 @@ validate_replace_rtx (from, to, insn)
 /* Try replacing every occurrence of FROM in INSN with TO.  */
 
 void
-validate_replace_rtx_group (from, to, insn)
-     rtx from, to, insn;
+validate_replace_rtx_group (rtx from, rtx to, rtx insn)
 {
   validate_replace_rtx_1 (&PATTERN (insn), from, to, insn);
 }
@@ -655,9 +657,7 @@ struct validate_replace_src_data
 };
 
 static void
-validate_replace_src_1 (x, data)
-     rtx *x;
-     void *data;
+validate_replace_src_1 (rtx *x, void *data)
 {
   struct validate_replace_src_data *d
     = (struct validate_replace_src_data *) data;
@@ -666,12 +666,10 @@ validate_replace_src_1 (x, data)
 }
 
 /* Try replacing every occurrence of FROM in INSN with TO, avoiding
-   SET_DESTs.  After all changes have been made, validate by seeing if
-   INSN is still valid.  */
+   SET_DESTs.  */
 
-int
-validate_replace_src (from, to, insn)
-     rtx from, to, insn;
+void
+validate_replace_src_group (rtx from, rtx to, rtx insn)
 {
   struct validate_replace_src_data d;
 
@@ -679,6 +677,14 @@ validate_replace_src (from, to, insn)
   d.to = to;
   d.insn = insn;
   note_uses (&PATTERN (insn), validate_replace_src_1, &d);
+}
+
+/* Same as validate_replace_src_group, but validate by seeing if
+   INSN is still valid.  */
+int
+validate_replace_src (rtx from, rtx to, rtx insn)
+{
+  validate_replace_src_group (from, to, insn);
   return apply_change_group ();
 }
 \f
@@ -688,10 +694,9 @@ validate_replace_src (from, to, insn)
    EQ and NE tests do not count.  */
 
 int
-next_insn_tests_no_inequality (insn)
-     rtx insn;
+next_insn_tests_no_inequality (rtx insn)
 {
-  register rtx next = next_cc0_user (insn);
+  rtx next = next_cc0_user (insn);
 
   /* If there is no next insn, we have to take the conservative choice.  */
   if (next == 0)
@@ -702,34 +707,6 @@ next_insn_tests_no_inequality (insn)
           || GET_CODE (next) == CALL_INSN)
          && ! inequality_comparisons_p (PATTERN (next)));
 }
-
-#if 0  /* This is useless since the insn that sets the cc's
-         must be followed immediately by the use of them.  */
-/* Return 1 if the CC value set up by INSN is not used.  */
-
-int
-next_insns_test_no_inequality (insn)
-     rtx insn;
-{
-  register rtx next = NEXT_INSN (insn);
-
-  for (; next != 0; next = NEXT_INSN (next))
-    {
-      if (GET_CODE (next) == CODE_LABEL
-         || GET_CODE (next) == BARRIER)
-       return 1;
-      if (GET_CODE (next) == NOTE)
-       continue;
-      if (inequality_comparisons_p (PATTERN (next)))
-       return 0;
-      if (sets_cc0_p (PATTERN (next)) == 1)
-       return 1;
-      if (! reg_mentioned_p (cc0_rtx, PATTERN (next)))
-       return 1;
-    }
-  return 1;
-}
-#endif
 #endif
 \f
 /* This is used by find_single_use to locate an rtx that contains exactly one
@@ -738,9 +715,7 @@ next_insns_test_no_inequality (insn)
    DEST that are being used to totally replace it are not counted.  */
 
 static rtx *
-find_single_use_1 (dest, loc)
-     rtx dest;
-     rtx *loc;
+find_single_use_1 (rtx dest, rtx *loc)
 {
   rtx x = *loc;
   enum rtx_code code = GET_CODE (x);
@@ -756,6 +731,7 @@ find_single_use_1 (dest, loc)
     case LABEL_REF:
     case SYMBOL_REF:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CLOBBER:
       return 0;
 
@@ -780,7 +756,7 @@ find_single_use_1 (dest, loc)
     case MEM:
     case SUBREG:
       return find_single_use_1 (dest, &XEXP (x, 0));
-      
+
     default:
       break;
     }
@@ -835,7 +811,7 @@ find_single_use_1 (dest, loc)
    sequel.  If so, return a pointer to the innermost rtx expression in which
    it is used.
 
-   If PLOC is non-zero, *PLOC is set to the insn containing the single use.
+   If PLOC is nonzero, *PLOC is set to the insn containing the single use.
 
    This routine will return usually zero either before flow is called (because
    there will be no LOG_LINKS notes) or after reload (because the REG_DEAD
@@ -850,10 +826,7 @@ find_single_use_1 (dest, loc)
    and last insn referencing DEST.  */
 
 rtx *
-find_single_use (dest, insn, ploc)
-     rtx dest;
-     rtx insn;
-     rtx *ploc;
+find_single_use (rtx dest, rtx insn, rtx *ploc)
 {
   rtx next;
   rtx *result;
@@ -916,11 +889,9 @@ find_single_use (dest, insn, ploc)
    class NO_REGS, see the comment for `register_operand'.  */
 
 int
-general_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+general_operand (rtx op, enum machine_mode mode)
 {
-  register enum rtx_code code = GET_CODE (op);
+  enum rtx_code code = GET_CODE (op);
 
   if (mode == VOIDmode)
     mode = GET_MODE (op);
@@ -933,6 +904,7 @@ general_operand (op, mode)
     return 0;
 
   if (GET_CODE (op) == CONST_INT
+      && mode != VOIDmode
       && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
     return 0;
 
@@ -952,24 +924,32 @@ general_operand (op, mode)
 
   if (code == SUBREG)
     {
+      rtx sub = SUBREG_REG (op);
+
 #ifdef INSN_SCHEDULING
       /* On machines that have insn scheduling, we want all memory
         reference to be explicit, so outlaw paradoxical SUBREGs.  */
-      if (GET_CODE (SUBREG_REG (op)) == MEM
-         && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
+      if (GET_CODE (sub) == MEM
+         && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (sub)))
        return 0;
 #endif
       /* Avoid memories with nonzero SUBREG_BYTE, as offsetting the memory
          may result in incorrect reference.  We should simplify all valid
          subregs of MEM anyway.  But allow this after reload because we
-        might be called from cleanup_subreg_operands. 
+        might be called from cleanup_subreg_operands.
 
         ??? This is a kludge.  */
       if (!reload_completed && SUBREG_BYTE (op) != 0
-         && GET_CODE (SUBREG_REG (op)) == MEM)
-        return 0;
+         && GET_CODE (sub) == MEM)
+       return 0;
 
-      op = SUBREG_REG (op);
+      /* FLOAT_MODE subregs can't be paradoxical.  Combine will occasionally
+        create such rtl, and we must reject it.  */
+      if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
+         && GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub)))
+       return 0;
+
+      op = sub;
       code = GET_CODE (op);
     }
 
@@ -980,7 +960,7 @@ general_operand (op, mode)
 
   if (code == MEM)
     {
-      register rtx y = XEXP (op, 0);
+      rtx y = XEXP (op, 0);
 
       if (! volatile_ok && MEM_VOLATILE_P (op))
        return 0;
@@ -1011,9 +991,7 @@ general_operand (op, mode)
    expressions in the machine description.  */
 
 int
-address_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+address_operand (rtx op, enum machine_mode mode)
 {
   return memory_address_p (mode, op);
 }
@@ -1033,41 +1011,44 @@ address_operand (op, mode)
    it is most consistent to keep this function from accepting them.  */
 
 int
-register_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+register_operand (rtx op, enum machine_mode mode)
 {
   if (GET_MODE (op) != mode && mode != VOIDmode)
     return 0;
 
   if (GET_CODE (op) == SUBREG)
     {
+      rtx sub = SUBREG_REG (op);
+
       /* Before reload, we can allow (SUBREG (MEM...)) as a register operand
         because it is guaranteed to be reloaded into one.
         Just make sure the MEM is valid in itself.
         (Ideally, (SUBREG (MEM)...) should not exist after reload,
         but currently it does result from (SUBREG (REG)...) where the
         reg went on the stack.)  */
-      if (! reload_completed && GET_CODE (SUBREG_REG (op)) == MEM)
+      if (! reload_completed && GET_CODE (sub) == MEM)
        return general_operand (op, mode);
 
-#ifdef CLASS_CANNOT_CHANGE_MODE
-      if (GET_CODE (SUBREG_REG (op)) == REG
-         && REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER
-         && (TEST_HARD_REG_BIT
-             (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
-              REGNO (SUBREG_REG (op))))
-         && CLASS_CANNOT_CHANGE_MODE_P (mode, GET_MODE (SUBREG_REG (op)))
-         && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_INT
-         && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_FLOAT)
+#ifdef CANNOT_CHANGE_MODE_CLASS
+      if (GET_CODE (sub) == REG
+         && REGNO (sub) < FIRST_PSEUDO_REGISTER
+         && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode)
+         && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT
+         && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_FLOAT)
        return 0;
 #endif
 
-      op = SUBREG_REG (op);
+      /* FLOAT_MODE subregs can't be paradoxical.  Combine will occasionally
+        create such rtl, and we must reject it.  */
+      if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
+         && GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub)))
+       return 0;
+
+      op = sub;
     }
 
   /* If we have an ADDRESSOF, consider it valid since it will be
-     converted into something that will not be a MEM. */
+     converted into something that will not be a MEM.  */
   if (GET_CODE (op) == ADDRESSOF)
     return 1;
 
@@ -1081,9 +1062,7 @@ register_operand (op, mode)
 /* Return 1 for a register in Pmode; ignore the tested mode.  */
 
 int
-pmode_register_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+pmode_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return register_operand (op, Pmode);
 }
@@ -1092,9 +1071,7 @@ pmode_register_operand (op, mode)
    or a hard register.  */
 
 int
-scratch_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+scratch_operand (rtx op, enum machine_mode mode)
 {
   if (GET_MODE (op) != mode && mode != VOIDmode)
     return 0;
@@ -1110,9 +1087,7 @@ scratch_operand (op, mode)
    expressions in the machine description.  */
 
 int
-immediate_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+immediate_operand (rtx op, enum machine_mode mode)
 {
   /* Don't accept CONST_INT or anything similar
      if the caller wants something floating.  */
@@ -1122,6 +1097,7 @@ immediate_operand (op, mode)
     return 0;
 
   if (GET_CODE (op) == CONST_INT
+      && mode != VOIDmode
       && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
     return 0;
 
@@ -1143,20 +1119,23 @@ immediate_operand (op, mode)
 /* Returns 1 if OP is an operand that is a CONST_INT.  */
 
 int
-const_int_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+const_int_operand (rtx op, enum machine_mode mode)
 {
-  return GET_CODE (op) == CONST_INT;
+  if (GET_CODE (op) != CONST_INT)
+    return 0;
+
+  if (mode != VOIDmode
+      && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
+    return 0;
+
+  return 1;
 }
 
 /* Returns 1 if OP is an operand that is a constant integer or constant
    floating-point number.  */
 
 int
-const_double_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+const_double_operand (rtx op, enum machine_mode mode)
 {
   /* Don't accept CONST_INT or anything similar
      if the caller wants something floating.  */
@@ -1173,9 +1152,7 @@ const_double_operand (op, mode)
 /* Return 1 if OP is a general operand that is not an immediate operand.  */
 
 int
-nonimmediate_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+nonimmediate_operand (rtx op, enum machine_mode mode)
 {
   return (general_operand (op, mode) && ! CONSTANT_P (op));
 }
@@ -1183,9 +1160,7 @@ nonimmediate_operand (op, mode)
 /* Return 1 if OP is a register reference or immediate value of mode MODE.  */
 
 int
-nonmemory_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+nonmemory_operand (rtx op, enum machine_mode mode)
 {
   if (CONSTANT_P (op))
     {
@@ -1197,11 +1172,12 @@ nonmemory_operand (op, mode)
        return 0;
 
       if (GET_CODE (op) == CONST_INT
+         && mode != VOIDmode
          && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
        return 0;
 
       return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
-             || mode == VOIDmode)
+              || mode == VOIDmode)
 #ifdef LEGITIMATE_PIC_OPERAND_P
              && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
 #endif
@@ -1238,9 +1214,7 @@ nonmemory_operand (op, mode)
    expressions in the machine description.  */
 
 int
-push_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+push_operand (rtx op, enum machine_mode mode)
 {
   unsigned int rounded_size = GET_MODE_SIZE (mode);
 
@@ -1270,7 +1244,7 @@ push_operand (op, mode)
 #ifdef STACK_GROWS_DOWNWARD
          || INTVAL (XEXP (XEXP (op, 1), 1)) != - (int) rounded_size
 #else
-         || INTVAL (XEXP (XEXP (op, 1), 1)) != rounded_size
+         || INTVAL (XEXP (XEXP (op, 1), 1)) != (int) rounded_size
 #endif
          )
        return 0;
@@ -1286,9 +1260,7 @@ push_operand (op, mode)
    expressions in the machine description.  */
 
 int
-pop_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+pop_operand (rtx op, enum machine_mode mode)
 {
   if (GET_CODE (op) != MEM)
     return 0;
@@ -1307,13 +1279,11 @@ pop_operand (op, mode)
 /* Return 1 if ADDR is a valid memory address for mode MODE.  */
 
 int
-memory_address_p (mode, addr)
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     register rtx addr;
+memory_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr)
 {
   if (GET_CODE (addr) == ADDRESSOF)
     return 1;
-  
+
   GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
   return 0;
 
@@ -1328,9 +1298,7 @@ memory_address_p (mode, addr)
    expressions in the machine description.  */
 
 int
-memory_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+memory_operand (rtx op, enum machine_mode mode)
 {
   rtx inner;
 
@@ -1353,15 +1321,13 @@ memory_operand (op, mode)
    that is, a memory reference whose address is a general_operand.  */
 
 int
-indirect_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+indirect_operand (rtx op, enum machine_mode mode)
 {
   /* Before reload, a SUBREG isn't in memory (see memory_operand, above).  */
   if (! reload_completed
       && GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == MEM)
     {
-      register int offset = SUBREG_BYTE (op);
+      int offset = SUBREG_BYTE (op);
       rtx inner = SUBREG_REG (op);
 
       if (mode != VOIDmode && GET_MODE (op) != mode)
@@ -1388,9 +1354,7 @@ indirect_operand (op, mode)
    MATCH_OPERATOR to recognize all the branch insns.  */
 
 int
-comparison_operator (op, mode)
-    register rtx op;
-    enum machine_mode mode;
+comparison_operator (rtx op, enum machine_mode mode)
 {
   return ((mode == VOIDmode || GET_MODE (op) == mode)
          && GET_RTX_CLASS (GET_CODE (op)) == '<');
@@ -1401,8 +1365,7 @@ comparison_operator (op, mode)
    Otherwise return -1.  */
 
 int
-asm_noperands (body)
-     rtx body;
+asm_noperands (rtx body)
 {
   switch (GET_CODE (body))
     {
@@ -1486,14 +1449,10 @@ asm_noperands (body)
    we don't store that info.  */
 
 const char *
-decode_asm_operands (body, operands, operand_locs, constraints, modes)
-     rtx body;
-     rtx *operands;
-     rtx **operand_locs;
-     const char **constraints;
-     enum machine_mode *modes;
-{
-  register int i;
+decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs,
+                    const char **constraints, enum machine_mode *modes)
+{
+  int i;
   int noperands;
   const char *template = 0;
 
@@ -1551,7 +1510,8 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes)
       template = ASM_OPERANDS_TEMPLATE (asmop);
     }
   else if (GET_CODE (body) == PARALLEL
-          && GET_CODE (XVECEXP (body, 0, 0)) == SET)
+          && GET_CODE (XVECEXP (body, 0, 0)) == SET
+          && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) == ASM_OPERANDS)
     {
       rtx asmop = SET_SRC (XVECEXP (body, 0, 0));
       int nparallel = XVECLEN (body, 0); /* Includes CLOBBERs.  */
@@ -1566,7 +1526,7 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes)
        {
          if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
            break;              /* Past last SET */
-         
+
          if (operands)
            operands[i] = SET_DEST (XVECEXP (body, 0, i));
          if (operand_locs)
@@ -1618,13 +1578,11 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes)
   return template;
 }
 
-/* Check if an asm_operand matches it's constraints. 
+/* Check if an asm_operand matches it's constraints.
    Return > 0 if ok, = 0 if bad, < 0 if inconclusive.  */
 
 int
-asm_operand_ok (op, constraint)
-     rtx op;
-     const char *constraint;
+asm_operand_ok (rtx op, const char *constraint)
 {
   int result = 0;
 
@@ -1634,18 +1592,21 @@ asm_operand_ok (op, constraint)
 
   while (*constraint)
     {
-      char c = *constraint++;
+      char c = *constraint;
+      int len;
       switch (c)
        {
+       case ',':
+         constraint++;
+         continue;
        case '=':
        case '+':
        case '*':
        case '%':
-       case '?':
        case '!':
        case '#':
        case '&':
-       case ',':
+       case '?':
          break;
 
        case '0': case '1': case '2': case '3': case '4':
@@ -1654,23 +1615,27 @@ asm_operand_ok (op, constraint)
             proper matching constraint, but we can't actually fail
             the check if they didn't.  Indicate that results are
             inconclusive.  */
-         result = -1;
-         break;
+         do
+           constraint++;
+         while (ISDIGIT (*constraint));
+         if (! result)
+           result = -1;
+         continue;
 
        case 'p':
          if (address_operand (op, VOIDmode))
-           return 1;
+           result = 1;
          break;
 
        case 'm':
        case 'V': /* non-offsettable */
          if (memory_operand (op, VOIDmode))
-           return 1;
+           result = 1;
          break;
 
        case 'o': /* offsettable */
          if (offsettable_nonstrict_memref_p (op))
-           return 1;
+           result = 1;
          break;
 
        case '<':
@@ -1684,43 +1649,35 @@ asm_operand_ok (op, constraint)
          if (GET_CODE (op) == MEM
              && (1
                  || GET_CODE (XEXP (op, 0)) == PRE_DEC
-                  || GET_CODE (XEXP (op, 0)) == POST_DEC))
-           return 1;
+                 || GET_CODE (XEXP (op, 0)) == POST_DEC))
+           result = 1;
          break;
 
        case '>':
          if (GET_CODE (op) == MEM
              && (1
                  || GET_CODE (XEXP (op, 0)) == PRE_INC
-                  || GET_CODE (XEXP (op, 0)) == POST_INC))
-           return 1;
+                 || GET_CODE (XEXP (op, 0)) == POST_INC))
+           result = 1;
          break;
 
        case 'E':
-#ifndef REAL_ARITHMETIC
-         /* Match any floating double constant, but only if
-            we can examine the bits of it reliably.  */
-         if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
-              || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
-             && GET_MODE (op) != VOIDmode && ! flag_pretend_float)
-           break;
-#endif
-         /* FALLTHRU */
-
        case 'F':
-         if (GET_CODE (op) == CONST_DOUBLE)
-           return 1;
+         if (GET_CODE (op) == CONST_DOUBLE
+             || (GET_CODE (op) == CONST_VECTOR
+                 && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
+           result = 1;
          break;
 
        case 'G':
          if (GET_CODE (op) == CONST_DOUBLE
-             && CONST_DOUBLE_OK_FOR_LETTER_P (op, 'G'))
-           return 1;
+             && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'G', constraint))
+           result = 1;
          break;
        case 'H':
          if (GET_CODE (op) == CONST_DOUBLE
-             && CONST_DOUBLE_OK_FOR_LETTER_P (op, 'H'))
-           return 1;
+             && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'H', constraint))
+           result = 1;
          break;
 
        case 's':
@@ -1736,82 +1693,100 @@ asm_operand_ok (op, constraint)
              && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
 #endif
              )
-           return 1;
+           result = 1;
          break;
 
        case 'n':
          if (GET_CODE (op) == CONST_INT
              || (GET_CODE (op) == CONST_DOUBLE
                  && GET_MODE (op) == VOIDmode))
-           return 1;
+           result = 1;
          break;
 
        case 'I':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'I', constraint))
+           result = 1;
          break;
        case 'J':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'J'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'J', constraint))
+           result = 1;
          break;
        case 'K':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'K'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', constraint))
+           result = 1;
          break;
        case 'L':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'L', constraint))
+           result = 1;
          break;
        case 'M':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'M'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'M', constraint))
+           result = 1;
          break;
        case 'N':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'N'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'N', constraint))
+           result = 1;
          break;
        case 'O':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'O'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'O', constraint))
+           result = 1;
          break;
        case 'P':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'P'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'P', constraint))
+           result = 1;
          break;
 
        case 'X':
-         return 1;
+         result = 1;
 
        case 'g':
          if (general_operand (op, VOIDmode))
-           return 1;
+           result = 1;
          break;
 
        default:
          /* For all other letters, we first check for a register class,
             otherwise it is an EXTRA_CONSTRAINT.  */
-         if (REG_CLASS_FROM_LETTER (c) != NO_REGS)
+         if (REG_CLASS_FROM_CONSTRAINT (c, constraint) != NO_REGS)
            {
            case 'r':
              if (GET_MODE (op) == BLKmode)
                break;
              if (register_operand (op, VOIDmode))
-               return 1;
+               result = 1;
+           }
+#ifdef EXTRA_CONSTRAINT_STR
+         if (EXTRA_CONSTRAINT_STR (op, c, constraint))
+           result = 1;
+         if (EXTRA_MEMORY_CONSTRAINT (c, constraint))
+           {
+             /* Every memory operand can be reloaded to fit.  */
+             if (memory_operand (op, VOIDmode))
+               result = 1;
+           }
+         if (EXTRA_ADDRESS_CONSTRAINT (c, constraint))
+           {
+             /* Every address operand can be reloaded to fit.  */
+             if (address_operand (op, VOIDmode))
+               result = 1;
            }
-#ifdef EXTRA_CONSTRAINT
-         if (EXTRA_CONSTRAINT (op, c))
-           return 1;
 #endif
          break;
        }
+      len = CONSTRAINT_LEN (c, constraint);
+      do
+       constraint++;
+      while (--len && *constraint);
+      if (len)
+       return 0;
     }
 
   return result;
@@ -1821,12 +1796,11 @@ asm_operand_ok (op, constraint)
    return the location (type rtx *) of the pointer to that constant term.
    Otherwise, return a null pointer.  */
 
-static rtx *
-find_constant_term_loc (p)
-     rtx *p;
+rtx *
+find_constant_term_loc (rtx *p)
 {
-  register rtx *tem;
-  register enum rtx_code code = GET_CODE (*p);
+  rtx *tem;
+  enum rtx_code code = GET_CODE (*p);
 
   /* If *P IS such a constant term, P is its location.  */
 
@@ -1876,8 +1850,7 @@ find_constant_term_loc (p)
    don't use it before reload.  */
 
 int
-offsettable_memref_p (op)
-     rtx op;
+offsettable_memref_p (rtx op)
 {
   return ((GET_CODE (op) == MEM)
          && offsettable_address_p (1, GET_MODE (op), XEXP (op, 0)));
@@ -1887,8 +1860,7 @@ offsettable_memref_p (op)
    consider pseudo-regs valid as index or base regs.  */
 
 int
-offsettable_nonstrict_memref_p (op)
-     rtx op;
+offsettable_nonstrict_memref_p (rtx op)
 {
   return ((GET_CODE (op) == MEM)
          && offsettable_address_p (0, GET_MODE (op), XEXP (op, 0)));
@@ -1905,16 +1877,13 @@ offsettable_nonstrict_memref_p (op)
    for the sake of use in reload.c.  */
 
 int
-offsettable_address_p (strictp, mode, y)
-     int strictp;
-     enum machine_mode mode;
-     register rtx y;
+offsettable_address_p (int strictp, enum machine_mode mode, rtx y)
 {
-  register enum rtx_code ycode = GET_CODE (y);
-  register rtx z;
+  enum rtx_code ycode = GET_CODE (y);
+  rtx z;
   rtx y1 = y;
   rtx *y2;
-  int (*addressp) PARAMS ((enum machine_mode, rtx)) =
+  int (*addressp) (enum machine_mode, rtx) =
     (strictp ? strict_memory_address_p : memory_address_p);
   unsigned int mode_sz = GET_MODE_SIZE (mode);
 
@@ -1958,9 +1927,15 @@ offsettable_address_p (strictp, mode, y)
   /* The offset added here is chosen as the maximum offset that
      any instruction could need to add when operating on something
      of the specified mode.  We assume that if Y and Y+c are
-     valid addresses then so is Y+d for all 0<d<c.  */
-
-  z = plus_constant_for_output (y, mode_sz - 1);
+     valid addresses then so is Y+d for all 0<d<c.  adjust_address will
+     go inside a LO_SUM here, so we do so as well.  */
+  if (GET_CODE (y) == LO_SUM
+      && mode != BLKmode
+      && mode_sz <= GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT)
+    z = gen_rtx_LO_SUM (GET_MODE (y), XEXP (y, 0),
+                       plus_constant (XEXP (y, 1), mode_sz - 1));
+  else
+    z = plus_constant (y, mode_sz - 1);
 
   /* Use QImode because an odd displacement may be automatically invalid
      for any wider mode.  But it should be valid for a single byte.  */
@@ -1974,94 +1949,21 @@ offsettable_address_p (strictp, mode, y)
    because the amount of the increment depends on the mode.  */
 
 int
-mode_dependent_address_p (addr)
-  rtx addr ATTRIBUTE_UNUSED; /* Maybe used in GO_IF_MODE_DEPENDENT_ADDRESS. */
+mode_dependent_address_p (rtx addr ATTRIBUTE_UNUSED /* Maybe used in GO_IF_MODE_DEPENDENT_ADDRESS. */)
 {
   GO_IF_MODE_DEPENDENT_ADDRESS (addr, win);
   return 0;
-  /* Label `win' might (not) be used via GO_IF_MODE_DEPENDENT_ADDRESS. */
+  /* Label `win' might (not) be used via GO_IF_MODE_DEPENDENT_ADDRESS.  */
  win: ATTRIBUTE_UNUSED_LABEL
   return 1;
 }
-
-/* Return 1 if OP is a general operand
-   other than a memory ref with a mode dependent address.  */
-
-int
-mode_independent_operand (op, mode)
-     enum machine_mode mode;
-     rtx op;
-{
-  rtx addr;
-
-  if (! general_operand (op, mode))
-    return 0;
-
-  if (GET_CODE (op) != MEM)
-    return 1;
-
-  addr = XEXP (op, 0);
-  GO_IF_MODE_DEPENDENT_ADDRESS (addr, lose);
-  return 1;
-  /* Label `lose' might (not) be used via GO_IF_MODE_DEPENDENT_ADDRESS. */
- lose: ATTRIBUTE_UNUSED_LABEL
-  return 0;
-}
-
-/* Given an operand OP that is a valid memory reference which
-   satisfies offsettable_memref_p, return a new memory reference whose
-   address has been adjusted by OFFSET.  OFFSET should be positive and
-   less than the size of the object referenced.  */
-
-rtx
-adj_offsettable_operand (op, offset)
-     rtx op;
-     int offset;
-{
-  register enum rtx_code code = GET_CODE (op);
-
-  if (code == MEM) 
-    {
-      register rtx y = XEXP (op, 0);
-      register rtx new;
-
-      if (CONSTANT_ADDRESS_P (y))
-       {
-         new = gen_rtx_MEM (GET_MODE (op),
-                            plus_constant_for_output (y, offset));
-         MEM_COPY_ATTRIBUTES (new, op);
-         return new;
-       }
-
-      if (GET_CODE (y) == PLUS)
-       {
-         rtx z = y;
-         register rtx *const_loc;
-
-         op = copy_rtx (op);
-         z = XEXP (op, 0);
-         const_loc = find_constant_term_loc (&z);
-         if (const_loc)
-           {
-             *const_loc = plus_constant_for_output (*const_loc, offset);
-             return op;
-           }
-       }
-
-      new = gen_rtx_MEM (GET_MODE (op), plus_constant_for_output (y, offset));
-      MEM_COPY_ATTRIBUTES (new, op);
-      return new;
-    }
-  abort ();
-}
 \f
 /* Like extract_insn, but save insn extracted and don't extract again, when
    called again for the same insn expecting that recog_data still contain the
    valid information.  This is used primary by gen_attr infrastructure that
    often does extract insn again and again.  */
 void
-extract_insn_cached (insn)
-     rtx insn;
+extract_insn_cached (rtx insn)
 {
   if (recog_data.insn == insn && INSN_CODE (insn) >= 0)
     return;
@@ -2071,8 +1973,7 @@ extract_insn_cached (insn)
 /* Do cached extract_insn, constrain_operand and complain about failures.
    Used by insn_attrtab.  */
 void
-extract_constrain_insn_cached (insn)
-     rtx insn;
+extract_constrain_insn_cached (rtx insn)
 {
   extract_insn_cached (insn);
   if (which_alternative == -1
@@ -2081,8 +1982,7 @@ extract_constrain_insn_cached (insn)
 }
 /* Do cached constrain_operand and complain about failures.  */
 int
-constrain_operands_cached (strict)
-       int strict;
+constrain_operands_cached (int strict)
 {
   if (which_alternative == -1)
     return constrain_operands (strict);
@@ -2093,8 +1993,7 @@ constrain_operands_cached (strict)
 /* Analyze INSN and fill in recog_data.  */
 
 void
-extract_insn (insn)
-     rtx insn;
+extract_insn (rtx insn)
 {
   int i;
   int icode;
@@ -2193,7 +2092,7 @@ extract_insn (insn)
    information from the constraint strings into a more usable form.
    The collected data is stored in recog_op_alt.  */
 void
-preprocess_constraints ()
+preprocess_constraints (void)
 {
   int i;
 
@@ -2221,13 +2120,16 @@ preprocess_constraints ()
 
          for (;;)
            {
-             char c = *p++;
+             char c = *p;
              if (c == '#')
                do
-                 c = *p++;
+                 c = *++p;
                while (c != ',' && c != '\0');
              if (c == ',' || c == '\0')
-               break;
+               {
+                 p++;
+                 break;
+               }
 
              switch (c)
                {
@@ -2247,13 +2149,17 @@ preprocess_constraints ()
                  break;
                case '&':
                  op_alt[j].earlyclobber = 1;
-                 break;                  
+                 break;
 
                case '0': case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
-                 op_alt[j].matches = c - '0';
-                 recog_op_alt[op_alt[j].matches][j].matched = i;
-                 break;
+                 {
+                   char *end;
+                   op_alt[j].matches = strtoul (p, &end, 10);
+                   recog_op_alt[op_alt[j].matches][j].matched = i;
+                   p = end;
+                 }
+                 continue;
 
                case 'm':
                  op_alt[j].memory_ok = 1;
@@ -2276,7 +2182,8 @@ preprocess_constraints ()
 
                case 'p':
                  op_alt[j].is_address = 1;
-                 op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) BASE_REG_CLASS];
+                 op_alt[j].class = reg_class_subunion[(int) op_alt[j].class]
+                   [(int) MODE_BASE_REG_CLASS (VOIDmode)];
                  break;
 
                case 'g': case 'r':
@@ -2284,14 +2191,33 @@ preprocess_constraints ()
                  break;
 
                default:
-                 op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) REG_CLASS_FROM_LETTER ((unsigned char)c)];
+                 if (EXTRA_MEMORY_CONSTRAINT (c, p))
+                   {
+                     op_alt[j].memory_ok = 1;
+                     break;
+                   }
+                 if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+                   {
+                     op_alt[j].is_address = 1;
+                     op_alt[j].class
+                       = (reg_class_subunion
+                          [(int) op_alt[j].class]
+                          [(int) MODE_BASE_REG_CLASS (VOIDmode)]);
+                     break;
+                   }
+
+                 op_alt[j].class
+                   = (reg_class_subunion
+                      [(int) op_alt[j].class]
+                      [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
                  break;
                }
+             p += CONSTRAINT_LEN (c, p);
            }
        }
     }
 }
+
 /* Check the operands of an insn against the insn's operand constraints
    and return 1 if they are valid.
    The information about the insn's operands, constraints, operand modes
@@ -2301,7 +2227,7 @@ preprocess_constraints ()
    alternative of constraints was matched: 0 for the first alternative,
    1 for the next, etc.
 
-   In addition, when two operands are match
+   In addition, when two operands are required to match
    and it happens that the output operand is (reg) while the
    input operand is --(reg) or ++(reg) (a pre-inc or pre-dec),
    make the output operand look like the input.
@@ -2310,7 +2236,7 @@ preprocess_constraints ()
    This is used in final, just before printing the assembler code and by
    the routines that determine an insn's attribute.
 
-   If STRICT is a positive non-zero value, it means that we have been
+   If STRICT is a positive nonzero value, it means that we have been
    called after reload has been completed.  In that case, we must
    do all checks strictly.  If it is zero, it means that we have been called
    before reload has completed.  In that case, we first try to see if we can
@@ -2325,13 +2251,12 @@ struct funny_match
 };
 
 int
-constrain_operands (strict)
-     int strict;
+constrain_operands (int strict)
 {
   const char *constraints[MAX_RECOG_OPERANDS];
   int matching_operands[MAX_RECOG_OPERANDS];
   int earlyclobber[MAX_RECOG_OPERANDS];
-  register int c;
+  int c;
 
   struct funny_match funny_match[MAX_RECOG_OPERANDS];
   int funny_match_index;
@@ -2348,18 +2273,19 @@ constrain_operands (strict)
 
   do
     {
-      register int opno;
+      int opno;
       int lose = 0;
       funny_match_index = 0;
 
       for (opno = 0; opno < recog_data.n_operands; opno++)
        {
-         register rtx op = recog_data.operand[opno];
+         rtx op = recog_data.operand[opno];
          enum machine_mode mode = GET_MODE (op);
-         register const char *p = constraints[opno];
+         const char *p = constraints[opno];
          int offset = 0;
          int win = 0;
          int val;
+         int len;
 
          earlyclobber[opno] = 0;
 
@@ -2384,9 +2310,16 @@ constrain_operands (strict)
          if (*p == 0 || *p == ',')
            win = 1;
 
-         while (*p && (c = *p++) != ',')
-           switch (c)
+         do
+           switch (c = *p, len = CONSTRAINT_LEN (c, p), c)
              {
+             case '\0':
+               len = 0;
+               break;
+             case ',':
+               c = '\0';
+               break;
+
              case '?':  case '!': case '*':  case '%':
              case '=':  case '+':
                break;
@@ -2394,8 +2327,10 @@ constrain_operands (strict)
              case '#':
                /* Ignore rest of this alternative as far as
                   constraint checking is concerned.  */
-               while (*p && *p != ',')
+               do
                  p++;
+               while (*p && *p != ',');
+               len = 0;
                break;
 
              case '&':
@@ -2404,45 +2339,55 @@ constrain_operands (strict)
 
              case '0':  case '1':  case '2':  case '3':  case '4':
              case '5':  case '6':  case '7':  case '8':  case '9':
+               {
+                 /* This operand must be the same as a previous one.
+                    This kind of constraint is used for instructions such
+                    as add when they take only two operands.
 
-               /* This operand must be the same as a previous one.
-                  This kind of constraint is used for instructions such
-                  as add when they take only two operands.
+                    Note that the lower-numbered operand is passed first.
 
-                  Note that the lower-numbered operand is passed first.
+                    If we are not testing strictly, assume that this
+                    constraint will be satisfied.  */
 
-                  If we are not testing strictly, assume that this constraint
-                  will be satisfied.  */
-               if (strict < 0)
-                 val = 1;
-               else
-                 {
-                   rtx op1 = recog_data.operand[c - '0'];
-                   rtx op2 = recog_data.operand[opno];
+                 char *end;
+                 int match;
 
-                   /* A unary operator may be accepted by the predicate,
-                      but it is irrelevant for matching constraints.  */
-                   if (GET_RTX_CLASS (GET_CODE (op1)) == '1')
-                     op1 = XEXP (op1, 0);
-                   if (GET_RTX_CLASS (GET_CODE (op2)) == '1')
-                     op2 = XEXP (op2, 0);
+                 match = strtoul (p, &end, 10);
+                 p = end;
 
-                   val = operands_match_p (op1, op2);
-                 }
+                 if (strict < 0)
+                   val = 1;
+                 else
+                   {
+                     rtx op1 = recog_data.operand[match];
+                     rtx op2 = recog_data.operand[opno];
 
-               matching_operands[opno] = c - '0';
-               matching_operands[c - '0'] = opno;
+                     /* A unary operator may be accepted by the predicate,
+                        but it is irrelevant for matching constraints.  */
+                     if (GET_RTX_CLASS (GET_CODE (op1)) == '1')
+                       op1 = XEXP (op1, 0);
+                     if (GET_RTX_CLASS (GET_CODE (op2)) == '1')
+                       op2 = XEXP (op2, 0);
 
-               if (val != 0)
-                 win = 1;
-               /* If output is *x and input is *--x,
-                  arrange later to change the output to *--x as well,
-                  since the output op is the one that will be printed.  */
-               if (val == 2 && strict > 0)
-                 {
-                   funny_match[funny_match_index].this = opno;
-                   funny_match[funny_match_index++].other = c - '0';
-                 }
+                     val = operands_match_p (op1, op2);
+                   }
+
+                 matching_operands[opno] = match;
+                 matching_operands[match] = opno;
+
+                 if (val != 0)
+                   win = 1;
+
+                 /* If output is *x and input is *--x, arrange later
+                    to change the output to *--x as well, since the
+                    output op is the one that will be printed.  */
+                 if (val == 2 && strict > 0)
+                   {
+                     funny_match[funny_match_index].this = opno;
+                     funny_match[funny_match_index++].other = match;
+                   }
+               }
+               len = 0;
                break;
 
              case 'p':
@@ -2502,27 +2447,17 @@ constrain_operands (strict)
                break;
 
              case 'E':
-#ifndef REAL_ARITHMETIC
-               /* Match any CONST_DOUBLE, but only if
-                  we can examine the bits of it reliably.  */
-               if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
-                    || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
-                   && GET_MODE (op) != VOIDmode && ! flag_pretend_float)
-                 break;
-#endif
-               if (GET_CODE (op) == CONST_DOUBLE)
-                 win = 1;
-               break;
-
              case 'F':
-               if (GET_CODE (op) == CONST_DOUBLE)
+               if (GET_CODE (op) == CONST_DOUBLE
+                   || (GET_CODE (op) == CONST_VECTOR
+                       && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
                  win = 1;
                break;
 
              case 'G':
              case 'H':
                if (GET_CODE (op) == CONST_DOUBLE
-                   && CONST_DOUBLE_OK_FOR_LETTER_P (op, c))
+                   && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
                  win = 1;
                break;
 
@@ -2552,7 +2487,7 @@ constrain_operands (strict)
              case 'O':
              case 'P':
                if (GET_CODE (op) == CONST_INT
-                   && CONST_OK_FOR_LETTER_P (INTVAL (op), c))
+                   && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
                  win = 1;
                break;
 
@@ -2583,7 +2518,8 @@ constrain_operands (strict)
                {
                  enum reg_class class;
 
-                 class = (c == 'r' ? GENERAL_REGS : REG_CLASS_FROM_LETTER (c));
+                 class = (c == 'r'
+                          ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p));
                  if (class != NO_REGS)
                    {
                      if (strict < 0
@@ -2595,13 +2531,36 @@ constrain_operands (strict)
                              && reg_fits_class_p (op, class, offset, mode)))
                        win = 1;
                    }
-#ifdef EXTRA_CONSTRAINT
-                 else if (EXTRA_CONSTRAINT (op, c))
+#ifdef EXTRA_CONSTRAINT_STR
+                 else if (EXTRA_CONSTRAINT_STR (op, c, p))
                    win = 1;
+
+                 if (EXTRA_MEMORY_CONSTRAINT (c, p))
+                   {
+                     /* Every memory operand can be reloaded to fit.  */
+                     if (strict < 0 && GET_CODE (op) == MEM)
+                       win = 1;
+
+                     /* Before reload, accept what reload can turn into mem.  */
+                     if (strict < 0 && CONSTANT_P (op))
+                       win = 1;
+
+                     /* During reload, accept a pseudo  */
+                     if (reload_in_progress && GET_CODE (op) == REG
+                         && REGNO (op) >= FIRST_PSEUDO_REGISTER)
+                       win = 1;
+                   }
+                 if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+                   {
+                     /* Every address operand can be reloaded to fit.  */
+                     if (strict < 0)
+                       win = 1;
+                   }
 #endif
                  break;
                }
              }
+         while (p += len, c);
 
          constraints[opno] = p;
          /* If this operand did not win somehow,
@@ -2669,18 +2628,15 @@ constrain_operands (strict)
    If REG occupies multiple hard regs, all of them must be in CLASS.  */
 
 int
-reg_fits_class_p (operand, class, offset, mode)
-     rtx operand;
-     register enum reg_class class;
-     int offset;
-     enum machine_mode mode;
+reg_fits_class_p (rtx operand, enum reg_class class, int offset,
+                 enum machine_mode mode)
 {
-  register int regno = REGNO (operand);
+  int regno = REGNO (operand);
   if (regno < FIRST_PSEUDO_REGISTER
       && TEST_HARD_REG_BIT (reg_class_contents[(int) class],
                            regno + offset))
     {
-      register int sr;
+      int sr;
       regno += offset;
       for (sr = HARD_REGNO_NREGS (regno, mode) - 1;
           sr > 0; sr--)
@@ -2693,115 +2649,139 @@ reg_fits_class_p (operand, class, offset, mode)
   return 0;
 }
 \f
+/* Split single instruction.  Helper function for split_all_insns.
+   Return last insn in the sequence if successful, or NULL if unsuccessful.  */
+static rtx
+split_insn (rtx insn)
+{
+  rtx set;
+  if (!INSN_P (insn))
+    ;
+  /* Don't split no-op move insns.  These should silently
+     disappear later in final.  Splitting such insns would
+     break the code that handles REG_NO_CONFLICT blocks.  */
+
+  else if ((set = single_set (insn)) != NULL && set_noop_p (set))
+    {
+      /* Nops get in the way while scheduling, so delete them
+         now if register allocation has already been done.  It
+         is too risky to try to do this before register
+         allocation, and there are unlikely to be very many
+         nops then anyways.  */
+      if (reload_completed)
+       delete_insn_and_edges (insn);
+    }
+  else
+    {
+      /* Split insns here to get max fine-grain parallelism.  */
+      rtx first = PREV_INSN (insn);
+      rtx last = try_split (PATTERN (insn), insn, 1);
+
+      if (last != insn)
+       {
+         /* try_split returns the NOTE that INSN became.  */
+         PUT_CODE (insn, NOTE);
+         NOTE_SOURCE_FILE (insn) = 0;
+         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+
+         /* ??? Coddle to md files that generate subregs in post-
+            reload splitters instead of computing the proper
+            hard register.  */
+         if (reload_completed && first != last)
+           {
+             first = NEXT_INSN (first);
+             while (1)
+               {
+                 if (INSN_P (first))
+                   cleanup_subreg_operands (first);
+                 if (first == last)
+                   break;
+                 first = NEXT_INSN (first);
+               }
+           }
+         return last;
+       }
+    }
+  return NULL_RTX;
+}
 /* Split all insns in the function.  If UPD_LIFE, update life info after.  */
 
 void
-split_all_insns (upd_life)
-     int upd_life;
+split_all_insns (int upd_life)
 {
   sbitmap blocks;
-  int changed;
-  int i;
+  bool changed;
+  basic_block bb;
 
-  blocks = sbitmap_alloc (n_basic_blocks);
+  blocks = sbitmap_alloc (last_basic_block);
   sbitmap_zero (blocks);
-  changed = 0;
+  changed = false;
 
-  for (i = n_basic_blocks - 1; i >= 0; --i)
+  FOR_EACH_BB_REVERSE (bb)
     {
-      basic_block bb = BASIC_BLOCK (i);
       rtx insn, next;
+      bool finish = false;
 
-      for (insn = bb->head; insn ; insn = next)
+      for (insn = bb->head; !finish ; insn = next)
        {
-         rtx set;
+         rtx last;
 
          /* Can't use `next_real_insn' because that might go across
             CODE_LABELS and short-out basic blocks.  */
          next = NEXT_INSN (insn);
-         if (! INSN_P (insn))
-           ;
-
-         /* Don't split no-op move insns.  These should silently
-            disappear later in final.  Splitting such insns would
-            break the code that handles REG_NO_CONFLICT blocks.  */
-
-         else if ((set = single_set (insn)) != NULL
-                  && set_noop_p (set))
+         finish = (insn == bb->end);
+         last = split_insn (insn);
+         if (last)
            {
-             /* Nops get in the way while scheduling, so delete them
-                now if register allocation has already been done.  It
-                is too risky to try to do this before register
-                allocation, and there are unlikely to be very many
-                nops then anyways.  */
-             if (reload_completed)
-               {
-                 PUT_CODE (insn, NOTE);
-                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-                 NOTE_SOURCE_FILE (insn) = 0;
-               }
+             /* The split sequence may include barrier, but the
+                BB boundary we are interested in will be set to previous
+                one.  */
+
+             while (GET_CODE (last) == BARRIER)
+               last = PREV_INSN (last);
+             SET_BIT (blocks, bb->index);
+             changed = true;
+             insn = last;
            }
-         else
-           {
-             /* Split insns here to get max fine-grain parallelism.  */
-             rtx first = PREV_INSN (insn);
-             rtx last = try_split (PATTERN (insn), insn, 1);
-
-             if (last != insn)
-               {
-                 SET_BIT (blocks, i);
-                 changed = 1;
-
-                 /* try_split returns the NOTE that INSN became.  */
-                 PUT_CODE (insn, NOTE);
-                 NOTE_SOURCE_FILE (insn) = 0;
-                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-
-                 /* ??? Coddle to md files that generate subregs in post-
-                    reload splitters instead of computing the proper 
-                    hard register.  */
-                 if (reload_completed && first != last)
-                   {
-                     first = NEXT_INSN (first);
-                     while (1)
-                       {
-                         if (INSN_P (first))
-                           cleanup_subreg_operands (first);
-                         if (first == last)
-                           break;
-                         first = NEXT_INSN (first);
-                       }
-                   }
+       }
+    }
 
-                 if (insn == bb->end)
-                   {
-                     bb->end = last;
-                     break;
-                   }
-               }
-           }
+  if (changed)
+    {
+      int old_last_basic_block = last_basic_block;
 
-         if (insn == bb->end)
-           break;
-       }
+      find_many_sub_basic_blocks (blocks);
 
-      /* ??? When we're called from just after reload, the CFG is in bad
-        shape, and we may have fallen off the end.  This could be fixed
-        by having reload not try to delete unreachable code.  Otherwise
-        assert we found the end insn.  */
-      if (insn == NULL && upd_life)
-       abort ();
+      if (old_last_basic_block != last_basic_block && upd_life)
+       blocks = sbitmap_resize (blocks, last_basic_block, 1);
     }
 
   if (changed && upd_life)
-    {
-      compute_bb_for_insn (get_max_uid ());
-      count_or_remove_death_notes (blocks, 1);
-      update_life_info (blocks, UPDATE_LIFE_LOCAL, PROP_DEATH_NOTES);
-    }
+    update_life_info (blocks, UPDATE_LIFE_GLOBAL_RM_NOTES,
+                     PROP_DEATH_NOTES | PROP_REG_INFO);
+
+#ifdef ENABLE_CHECKING
+  verify_flow_info ();
+#endif
 
   sbitmap_free (blocks);
 }
+
+/* Same as split_all_insns, but do not expect CFG to be available.
+   Used by machine dependent reorg passes.  */
+
+void
+split_all_insns_noflow (void)
+{
+  rtx next, insn;
+
+  for (insn = get_insns (); insn; insn = next)
+    {
+      next = NEXT_INSN (insn);
+      split_insn (insn);
+    }
+  return;
+}
 \f
 #ifdef HAVE_peephole2
 struct peep2_insn_data
@@ -2823,8 +2803,7 @@ static int peep2_current;
    in a multi-insn pattern.  */
 
 rtx
-peep2_next_insn (n)
-     int n;
+peep2_next_insn (int n)
 {
   if (n >= MAX_INSNS_PER_PEEP2 + 1)
     abort ();
@@ -2842,9 +2821,7 @@ peep2_next_insn (n)
    after `current'.  */
 
 int
-peep2_regno_dead_p (ofs, regno)
-     int ofs;
-     int regno;
+peep2_regno_dead_p (int ofs, int regno)
 {
   if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
     abort ();
@@ -2862,9 +2839,7 @@ peep2_regno_dead_p (ofs, regno)
 /* Similarly for a REG.  */
 
 int
-peep2_reg_dead_p (ofs, reg)
-     int ofs;
-     rtx reg;
+peep2_reg_dead_p (int ofs, rtx reg)
 {
   int regno, n;
 
@@ -2898,11 +2873,8 @@ peep2_reg_dead_p (ofs, reg)
    returned.  */
 
 rtx
-peep2_find_free_register (from, to, class_str, mode, reg_set)
-     int from, to;
-     const char *class_str;
-     enum machine_mode mode;
-     HARD_REG_SET *reg_set;
+peep2_find_free_register (int from, int to, const char *class_str,
+                         enum machine_mode mode, HARD_REG_SET *reg_set)
 {
   static int search_ofs;
   enum reg_class class;
@@ -2936,7 +2908,7 @@ peep2_find_free_register (from, to, class_str, mode, reg_set)
     }
 
   class = (class_str[0] == 'r' ? GENERAL_REGS
-          : REG_CLASS_FROM_LETTER (class_str[0]));
+          : REG_CLASS_FROM_CONSTRAINT (class_str[0], class_str));
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
@@ -2997,20 +2969,22 @@ peep2_find_free_register (from, to, class_str, mode, reg_set)
   return NULL_RTX;
 }
 
-/* Perform the peephole2 optimization pass. */
+/* Perform the peephole2 optimization pass.  */
 
 void
-peephole2_optimize (dump_file)
-     FILE *dump_file ATTRIBUTE_UNUSED;
+peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
 {
   regset_head rs_heads[MAX_INSNS_PER_PEEP2 + 2];
   rtx insn, prev;
   regset live;
-  int i, b;
+  int i;
+  basic_block bb;
 #ifdef HAVE_conditional_execution
   sbitmap blocks;
-  int changed;
+  bool changed;
 #endif
+  bool do_cleanup_cfg = false;
+  bool do_rebuild_jump_labels = false;
 
   /* Initialize the regsets we're going to use.  */
   for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
@@ -3018,16 +2992,15 @@ peephole2_optimize (dump_file)
   live = INITIALIZE_REG_SET (rs_heads[i]);
 
 #ifdef HAVE_conditional_execution
-  blocks = sbitmap_alloc (n_basic_blocks);
+  blocks = sbitmap_alloc (last_basic_block);
   sbitmap_zero (blocks);
-  changed = 0;
+  changed = false;
 #else
   count_or_remove_death_notes (NULL, 1);
 #endif
 
-  for (b = n_basic_blocks - 1; b >= 0; --b)
+  FOR_EACH_BB_REVERSE (bb)
     {
-      basic_block bb = BASIC_BLOCK (b);
       struct propagate_block_info *pbi;
 
       /* Indicate that all slots except the last holds invalid data.  */
@@ -3053,8 +3026,10 @@ peephole2_optimize (dump_file)
          prev = PREV_INSN (insn);
          if (INSN_P (insn))
            {
-             rtx try;
+             rtx try, before_try, x;
              int match_len;
+             rtx note;
+             bool was_call = false;
 
              /* Record this insn.  */
              if (--peep2_current < 0)
@@ -3067,19 +3042,132 @@ peephole2_optimize (dump_file)
              try = peephole2_insns (PATTERN (insn), insn, &match_len);
              if (try != NULL)
                {
+                 /* If we are splitting a CALL_INSN, look for the CALL_INSN
+                    in SEQ and copy our CALL_INSN_FUNCTION_USAGE and other
+                    cfg-related call notes.  */
+                 for (i = 0; i <= match_len; ++i)
+                   {
+                     int j;
+                     rtx old_insn, new_insn, note;
+
+                     j = i + peep2_current;
+                     if (j >= MAX_INSNS_PER_PEEP2 + 1)
+                       j -= MAX_INSNS_PER_PEEP2 + 1;
+                     old_insn = peep2_insn_data[j].insn;
+                     if (GET_CODE (old_insn) != CALL_INSN)
+                       continue;
+                     was_call = true;
+
+                     new_insn = try;
+                     while (new_insn != NULL_RTX)
+                       {
+                         if (GET_CODE (new_insn) == CALL_INSN)
+                           break;
+                         new_insn = NEXT_INSN (new_insn);
+                       }
+
+                     if (new_insn == NULL_RTX)
+                       abort ();
+
+                     CALL_INSN_FUNCTION_USAGE (new_insn)
+                       = CALL_INSN_FUNCTION_USAGE (old_insn);
+
+                     for (note = REG_NOTES (old_insn);
+                          note;
+                          note = XEXP (note, 1))
+                       switch (REG_NOTE_KIND (note))
+                         {
+                         case REG_NORETURN:
+                         case REG_SETJMP:
+                         case REG_ALWAYS_RETURN:
+                           REG_NOTES (new_insn)
+                             = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
+                                                  XEXP (note, 0),
+                                                  REG_NOTES (new_insn));
+                         default:
+                           /* Discard all other reg notes.  */
+                           break;
+                         }
+
+                     /* Croak if there is another call in the sequence.  */
+                     while (++i <= match_len)
+                       {
+                         j = i + peep2_current;
+                         if (j >= MAX_INSNS_PER_PEEP2 + 1)
+                           j -= MAX_INSNS_PER_PEEP2 + 1;
+                         old_insn = peep2_insn_data[j].insn;
+                         if (GET_CODE (old_insn) == CALL_INSN)
+                           abort ();
+                       }
+                     break;
+                   }
+
                  i = match_len + peep2_current;
                  if (i >= MAX_INSNS_PER_PEEP2 + 1)
                    i -= MAX_INSNS_PER_PEEP2 + 1;
 
+                 note = find_reg_note (peep2_insn_data[i].insn,
+                                       REG_EH_REGION, NULL_RTX);
+
                  /* Replace the old sequence with the new.  */
-                 flow_delete_insn_chain (insn, peep2_insn_data[i].insn);
-                 try = emit_insn_after (try, prev);
+                 try = emit_insn_after_setloc (try, peep2_insn_data[i].insn,
+                                               INSN_LOCATOR (peep2_insn_data[i].insn));
+                 before_try = PREV_INSN (insn);
+                 delete_insn_chain (insn, peep2_insn_data[i].insn);
 
-                 /* Adjust the basic block boundaries.  */
-                 if (peep2_insn_data[i].insn == bb->end)
-                   bb->end = try;
-                 if (insn == bb->head)
-                   bb->head = NEXT_INSN (prev);
+                 /* Re-insert the EH_REGION notes.  */
+                 if (note || (was_call && nonlocal_goto_handler_labels))
+                   {
+                     edge eh_edge;
+
+                     for (eh_edge = bb->succ; eh_edge
+                          ; eh_edge = eh_edge->succ_next)
+                       if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
+                         break;
+
+                     for (x = try ; x != before_try ; x = PREV_INSN (x))
+                       if (GET_CODE (x) == CALL_INSN
+                           || (flag_non_call_exceptions
+                               && may_trap_p (PATTERN (x))
+                               && !find_reg_note (x, REG_EH_REGION, NULL)))
+                         {
+                           if (note)
+                             REG_NOTES (x)
+                               = gen_rtx_EXPR_LIST (REG_EH_REGION,
+                                                    XEXP (note, 0),
+                                                    REG_NOTES (x));
+
+                           if (x != bb->end && eh_edge)
+                             {
+                               edge nfte, nehe;
+                               int flags;
+
+                               nfte = split_block (bb, x);
+                               flags = (eh_edge->flags
+                                        & (EDGE_EH | EDGE_ABNORMAL));
+                               if (GET_CODE (x) == CALL_INSN)
+                                 flags |= EDGE_ABNORMAL_CALL;
+                               nehe = make_edge (nfte->src, eh_edge->dest,
+                                                 flags);
+
+                               nehe->probability = eh_edge->probability;
+                               nfte->probability
+                                 = REG_BR_PROB_BASE - nehe->probability;
+
+                               do_cleanup_cfg |= purge_dead_edges (nfte->dest);
+#ifdef HAVE_conditional_execution
+                               SET_BIT (blocks, nfte->dest->index);
+                               changed = true;
+#endif
+                               bb = nfte->src;
+                               eh_edge = nehe;
+                             }
+                         }
+
+                     /* Converting possibly trapping insn to non-trapping is
+                        possible.  Zap dummy outgoing edges.  */
+                     do_cleanup_cfg |= purge_dead_edges (bb);
+                   }
 
 #ifdef HAVE_conditional_execution
                  /* With conditional execution, we cannot back up the
@@ -3087,8 +3175,8 @@ peephole2_optimize (dump_file)
                     death data structures are not so self-contained.
                     So record that we've made a modification to this
                     block and update life information at the end.  */
-                 SET_BIT (blocks, b);
-                 changed = 1;
+                 SET_BIT (blocks, bb->index);
+                 changed = true;
 
                  for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
                    peep2_insn_data[i].insn = NULL_RTX;
@@ -3101,25 +3189,35 @@ peephole2_optimize (dump_file)
                  COPY_REG_SET (live, peep2_insn_data[i].live_before);
 
                  /* Update life information for the new sequence.  */
+                 x = try;
                  do
                    {
-                     if (INSN_P (try))
+                     if (INSN_P (x))
                        {
                          if (--i < 0)
                            i = MAX_INSNS_PER_PEEP2;
-                         peep2_insn_data[i].insn = try;
-                         propagate_one_insn (pbi, try);
+                         peep2_insn_data[i].insn = x;
+                         propagate_one_insn (pbi, x);
                          COPY_REG_SET (peep2_insn_data[i].live_before, live);
                        }
-                     try = PREV_INSN (try);
+                     x = PREV_INSN (x);
                    }
-                 while (try != prev);
+                 while (x != prev);
 
                  /* ??? Should verify that LIVE now matches what we
                     had before the new sequence.  */
 
                  peep2_current = i;
 #endif
+
+                 /* If we generated a jump instruction, it won't have
+                    JUMP_LABEL set.  Recompute after we're done.  */
+                 for (x = try; x != before_try; x = PREV_INSN (x))
+                   if (GET_CODE (x) == JUMP_INSN)
+                     {
+                       do_rebuild_jump_labels = true;
+                       break;
+                     }
                }
            }
 
@@ -3134,10 +3232,133 @@ peephole2_optimize (dump_file)
     FREE_REG_SET (peep2_insn_data[i].live_before);
   FREE_REG_SET (live);
 
+  if (do_rebuild_jump_labels)
+    rebuild_jump_labels (get_insns ());
+
+  /* If we eliminated EH edges, we may be able to merge blocks.  Further,
+     we've changed global life since exception handlers are no longer
+     reachable.  */
+  if (do_cleanup_cfg)
+    {
+      cleanup_cfg (0);
+      update_life_info (0, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES);
+    }
 #ifdef HAVE_conditional_execution
-  count_or_remove_death_notes (blocks, 1);
-  update_life_info (blocks, UPDATE_LIFE_LOCAL, PROP_DEATH_NOTES);
+  else
+    {
+      count_or_remove_death_notes (blocks, 1);
+      update_life_info (blocks, UPDATE_LIFE_LOCAL, PROP_DEATH_NOTES);
+    }
   sbitmap_free (blocks);
 #endif
 }
 #endif /* HAVE_peephole2 */
+
+/* Common predicates for use with define_bypass.  */
+
+/* True if the dependency between OUT_INSN and IN_INSN is on the store
+   data not the address operand(s) of the store.  IN_INSN must be
+   single_set.  OUT_INSN must be either a single_set or a PARALLEL with
+   SETs inside.  */
+
+int
+store_data_bypass_p (rtx out_insn, rtx in_insn)
+{
+  rtx out_set, in_set;
+
+  in_set = single_set (in_insn);
+  if (! in_set)
+    abort ();
+
+  if (GET_CODE (SET_DEST (in_set)) != MEM)
+    return false;
+
+  out_set = single_set (out_insn);
+  if (out_set)
+    {
+      if (reg_mentioned_p (SET_DEST (out_set), SET_DEST (in_set)))
+       return false;
+    }
+  else
+    {
+      rtx out_pat;
+      int i;
+
+      out_pat = PATTERN (out_insn);
+      if (GET_CODE (out_pat) != PARALLEL)
+       abort ();
+
+      for (i = 0; i < XVECLEN (out_pat, 0); i++)
+       {
+         rtx exp = XVECEXP (out_pat, 0, i);
+
+         if (GET_CODE (exp) == CLOBBER)
+           continue;
+
+         if (GET_CODE (exp) != SET)
+           abort ();
+
+         if (reg_mentioned_p (SET_DEST (exp), SET_DEST (in_set)))
+           return false;
+       }
+    }
+
+  return true;
+}
+
+/* True if the dependency between OUT_INSN and IN_INSN is in the IF_THEN_ELSE
+   condition, and not the THEN or ELSE branch.  OUT_INSN may be either a single
+   or multiple set; IN_INSN should be single_set for truth, but for convenience
+   of insn categorization may be any JUMP or CALL insn.  */
+
+int
+if_test_bypass_p (rtx out_insn, rtx in_insn)
+{
+  rtx out_set, in_set;
+
+  in_set = single_set (in_insn);
+  if (! in_set)
+    {
+      if (GET_CODE (in_insn) == JUMP_INSN || GET_CODE (in_insn) == CALL_INSN)
+       return false;
+      abort ();
+    }
+
+  if (GET_CODE (SET_SRC (in_set)) != IF_THEN_ELSE)
+    return false;
+  in_set = SET_SRC (in_set);
+
+  out_set = single_set (out_insn);
+  if (out_set)
+    {
+      if (reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 1))
+         || reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 2)))
+       return false;
+    }
+  else
+    {
+      rtx out_pat;
+      int i;
+
+      out_pat = PATTERN (out_insn);
+      if (GET_CODE (out_pat) != PARALLEL)
+       abort ();
+
+      for (i = 0; i < XVECLEN (out_pat, 0); i++)
+       {
+         rtx exp = XVECEXP (out_pat, 0, i);
+
+         if (GET_CODE (exp) == CLOBBER)
+           continue;
+
+         if (GET_CODE (exp) != SET)
+           abort ();
+
+         if (reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 1))
+             || reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 2)))
+           return false;
+       }
+    }
+
+  return true;
+}