OSDN Git Service

* tree-inline.c (find_builtin_longjmp_call): Save and restore
[pf3gnuchains/gcc-fork.git] / gcc / recog.c
index 874d567..6f4a733 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used by or related to instruction recognition.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
 /* 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 GCC.
 
 
 This file is part of GCC.
 
@@ -22,6 +22,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "insn-config.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "insn-config.h"
@@ -157,11 +159,11 @@ check_asm_operands (x)
       const char *c = constraints[i];
       if (c[0] == '%')
        c++;
       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))
        c = constraints[c[0] - '0'];
 
       if (! asm_operand_ok (operands[i], c))
-        return 0;
+       return 0;
     }
 
   return 1;
     }
 
   return 1;
@@ -191,7 +193,7 @@ static int num_changes = 0;
    an INSN, CALL_INSN, or JUMP_INSN, the insn will be re-recognized with
    the change in place.
 
    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.
 
    performed as a group.  In that case, the changes will be stored.  The
    function `apply_change_group' will validate and apply the changes.
 
@@ -227,11 +229,11 @@ validate_change (object, loc, new, in_group)
       else
        changes_allocated *= 2;
 
       else
        changes_allocated *= 2;
 
-      changes = 
-       (change_t*) xrealloc (changes, 
-                             sizeof (change_t) * changes_allocated); 
+      changes =
+       (change_t*) xrealloc (changes,
+                             sizeof (change_t) * changes_allocated);
     }
     }
-  
+
   changes[num_changes].object = object;
   changes[num_changes].loc = loc;
   changes[num_changes].old = old;
   changes[num_changes].object = object;
   changes[num_changes].loc = loc;
   changes[num_changes].old = old;
@@ -272,7 +274,7 @@ insn_invalid_p (insn)
                     ? &num_clobbers : 0);
   int is_asm = icode < 0 && asm_noperands (PATTERN (insn)) >= 0;
 
                     ? &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)))
   /* 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)))
@@ -308,6 +310,13 @@ insn_invalid_p (insn)
   return 0;
 }
 
   return 0;
 }
 
+/* Return number of changes made and not validated yet.  */
+int
+num_changes_pending ()
+{
+  return num_changes;
+}
+
 /* Apply a group of changes previously issued with `validate_change'.
    Return 1 if all changes are valid, zero otherwise.  */
 
 /* Apply a group of changes previously issued with `validate_change'.
    Return 1 if all changes are valid, zero otherwise.  */
 
@@ -362,7 +371,7 @@ apply_change_group ()
                  int j;
 
                  newpat
                  int j;
 
                  newpat
-                   = gen_rtx_PARALLEL (VOIDmode, 
+                   = 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);
                                        rtvec_alloc (XVECLEN (pat, 0) - 1));
                  for (j = 0; j < XVECLEN (newpat, 0); j++)
                    XVECEXP (newpat, 0, j) = XVECEXP (pat, 0, j);
@@ -392,6 +401,14 @@ apply_change_group ()
 
   if (i == num_changes)
     {
 
   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;
     }
       num_changes = 0;
       return 1;
     }
@@ -507,12 +524,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
     {
     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.  */
          ??? We may want later to remove this, once simplification is
          separated from this function.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)
        validate_change (object, loc,
        validate_change (object, loc,
-                        plus_constant (XEXP (x, 0), INTVAL (XEXP (x, 1))), 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
       break;
     case MINUS:
       if (GET_CODE (XEXP (x, 1)) == CONST_INT
@@ -662,11 +680,10 @@ validate_replace_src_1 (x, data)
 }
 
 /* Try replacing every occurrence of FROM in INSN with TO, avoiding
 }
 
 /* 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)
+void
+validate_replace_src_group (from, to, insn)
      rtx from, to, insn;
 {
   struct validate_replace_src_data d;
      rtx from, to, insn;
 {
   struct validate_replace_src_data d;
@@ -675,6 +692,15 @@ validate_replace_src (from, to, insn)
   d.to = to;
   d.insn = insn;
   note_uses (&PATTERN (insn), validate_replace_src_1, &d);
   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 (from, to, insn)
+     rtx from, to, insn;
+{
+  validate_replace_src_group (from, to, insn);
   return apply_change_group ();
 }
 \f
   return apply_change_group ();
 }
 \f
@@ -752,6 +778,7 @@ find_single_use_1 (dest, loc)
     case LABEL_REF:
     case SYMBOL_REF:
     case CONST_DOUBLE:
     case LABEL_REF:
     case SYMBOL_REF:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CLOBBER:
       return 0;
 
     case CLOBBER:
       return 0;
 
@@ -776,7 +803,7 @@ find_single_use_1 (dest, loc)
     case MEM:
     case SUBREG:
       return find_single_use_1 (dest, &XEXP (x, 0));
     case MEM:
     case SUBREG:
       return find_single_use_1 (dest, &XEXP (x, 0));
-      
+
     default:
       break;
     }
     default:
       break;
     }
@@ -831,7 +858,7 @@ find_single_use_1 (dest, loc)
    sequel.  If so, return a pointer to the innermost rtx expression in which
    it is used.
 
    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
 
    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
@@ -929,6 +956,7 @@ general_operand (op, mode)
     return 0;
 
   if (GET_CODE (op) == CONST_INT
     return 0;
 
   if (GET_CODE (op) == CONST_INT
+      && mode != VOIDmode
       && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
     return 0;
 
       && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
     return 0;
 
@@ -948,24 +976,32 @@ general_operand (op, mode)
 
   if (code == SUBREG)
     {
 
   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.  */
 #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
        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
 
         ??? 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);
     }
 
       code = GET_CODE (op);
     }
 
@@ -1038,28 +1074,33 @@ register_operand (op, mode)
 
   if (GET_CODE (op) == SUBREG)
     {
 
   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.)  */
       /* 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);
 
        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
 
        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
     }
 
   /* If we have an ADDRESSOF, consider it valid since it will be
@@ -1118,6 +1159,7 @@ immediate_operand (op, mode)
     return 0;
 
   if (GET_CODE (op) == CONST_INT
     return 0;
 
   if (GET_CODE (op) == CONST_INT
+      && mode != VOIDmode
       && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
     return 0;
 
       && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
     return 0;
 
@@ -1200,6 +1242,7 @@ nonmemory_operand (op, mode)
        return 0;
 
       if (GET_CODE (op) == CONST_INT
        return 0;
 
       if (GET_CODE (op) == CONST_INT
+         && mode != VOIDmode
          && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
        return 0;
 
          && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
        return 0;
 
@@ -1273,7 +1316,7 @@ push_operand (op, mode)
 #ifdef STACK_GROWS_DOWNWARD
          || INTVAL (XEXP (XEXP (op, 1), 1)) != - (int) rounded_size
 #else
 #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;
 #endif
          )
        return 0;
@@ -1316,7 +1359,7 @@ memory_address_p (mode, addr)
 {
   if (GET_CODE (addr) == ADDRESSOF)
     return 1;
 {
   if (GET_CODE (addr) == ADDRESSOF)
     return 1;
-  
+
   GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
   return 0;
 
   GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
   return 0;
 
@@ -1554,7 +1597,8 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes)
       template = ASM_OPERANDS_TEMPLATE (asmop);
     }
   else if (GET_CODE (body) == PARALLEL
       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.  */
     {
       rtx asmop = SET_SRC (XVECEXP (body, 0, 0));
       int nparallel = XVECLEN (body, 0); /* Includes CLOBBERs.  */
@@ -1569,7 +1613,7 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes)
        {
          if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
            break;              /* Past last SET */
        {
          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)
          if (operands)
            operands[i] = SET_DEST (XVECEXP (body, 0, i));
          if (operand_locs)
@@ -1621,7 +1665,7 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes)
   return template;
 }
 
   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
    Return > 0 if ok, = 0 if bad, < 0 if inconclusive.  */
 
 int
@@ -1637,18 +1681,21 @@ asm_operand_ok (op, constraint)
 
   while (*constraint)
     {
 
   while (*constraint)
     {
-      char c = *constraint++;
+      char c = *constraint;
+      int len;
       switch (c)
        {
       switch (c)
        {
+       case ',':
+         constraint++;
+         continue;
        case '=':
        case '+':
        case '*':
        case '%':
        case '=':
        case '+':
        case '*':
        case '%':
-       case '?':
        case '!':
        case '#':
        case '&':
        case '!':
        case '#':
        case '&':
-       case ',':
+       case '?':
          break;
 
        case '0': case '1': case '2': case '3': case '4':
          break;
 
        case '0': case '1': case '2': case '3': case '4':
@@ -1657,25 +1704,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.  */
             proper matching constraint, but we can't actually fail
             the check if they didn't.  Indicate that results are
             inconclusive.  */
-         while (*constraint >= '0' && *constraint <= '9')
+         do
            constraint++;
            constraint++;
-         result = -1;
-         break;
+         while (ISDIGIT (*constraint));
+         if (! result)
+           result = -1;
+         continue;
 
        case 'p':
          if (address_operand (op, VOIDmode))
 
        case 'p':
          if (address_operand (op, VOIDmode))
-           return 1;
+           result = 1;
          break;
 
        case 'm':
        case 'V': /* non-offsettable */
          if (memory_operand (op, VOIDmode))
          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))
          break;
 
        case 'o': /* offsettable */
          if (offsettable_nonstrict_memref_p (op))
-           return 1;
+           result = 1;
          break;
 
        case '<':
          break;
 
        case '<':
@@ -1689,43 +1738,35 @@ asm_operand_ok (op, constraint)
          if (GET_CODE (op) == MEM
              && (1
                  || GET_CODE (XEXP (op, 0)) == PRE_DEC
          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
          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':
          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':
        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
          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
          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':
          break;
 
        case 's':
@@ -1741,82 +1782,100 @@ asm_operand_ok (op, constraint)
              && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
 #endif
              )
              && (! 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))
          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
          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
          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
          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
          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
          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
          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
          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
          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':
          break;
 
        case 'X':
-         return 1;
+         result = 1;
 
        case 'g':
          if (general_operand (op, VOIDmode))
 
        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.  */
          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))
            {
            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;
        }
 #endif
          break;
        }
+      len = CONSTRAINT_LEN (c, constraint);
+      do
+       constraint++;
+      while (--len && *constraint);
+      if (len)
+       return 0;
     }
 
   return result;
     }
 
   return result;
@@ -1965,7 +2024,9 @@ offsettable_address_p (strictp, mode, y)
      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.  adjust_address will
      go inside a LO_SUM here, so we do so as well.  */
      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.  adjust_address will
      go inside a LO_SUM here, so we do so as well.  */
-  if (GET_CODE (y) == LO_SUM)
+  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 = gen_rtx_LO_SUM (GET_MODE (y), XEXP (y, 0),
                        plus_constant (XEXP (y, 1), mode_sz - 1));
   else
@@ -2183,13 +2244,16 @@ preprocess_constraints ()
 
          for (;;)
            {
 
          for (;;)
            {
-             char c = *p++;
+             char c = *p;
              if (c == '#')
                do
              if (c == '#')
                do
-                 c = *p++;
+                 c = *++p;
                while (c != ',' && c != '\0');
              if (c == ',' || c == '\0')
                while (c != ',' && c != '\0');
              if (c == ',' || c == '\0')
-               break;
+               {
+                 p++;
+                 break;
+               }
 
              switch (c)
                {
 
              switch (c)
                {
@@ -2209,17 +2273,17 @@ preprocess_constraints ()
                  break;
                case '&':
                  op_alt[j].earlyclobber = 1;
                  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':
                  {
                    char *end;
 
                case '0': case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
                  {
                    char *end;
-                   op_alt[j].matches = strtoul (p - 1, &end, 10);
+                   op_alt[j].matches = strtoul (p, &end, 10);
                    recog_op_alt[op_alt[j].matches][j].matched = i;
                    p = end;
                  }
                    recog_op_alt[op_alt[j].matches][j].matched = i;
                    p = end;
                  }
-                 break;
+                 continue;
 
                case 'm':
                  op_alt[j].memory_ok = 1;
 
                case 'm':
                  op_alt[j].memory_ok = 1;
@@ -2242,7 +2306,8 @@ preprocess_constraints ()
 
                case 'p':
                  op_alt[j].is_address = 1;
 
                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':
                  break;
 
                case 'g': case 'r':
@@ -2250,14 +2315,33 @@ preprocess_constraints ()
                  break;
 
                default:
                  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;
                }
                  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
 /* 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
@@ -2267,7 +2351,7 @@ preprocess_constraints ()
    alternative of constraints was matched: 0 for the first alternative,
    1 for the next, etc.
 
    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.
    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.
@@ -2276,7 +2360,7 @@ preprocess_constraints ()
    This is used in final, just before printing the assembler code and by
    the routines that determine an insn's attribute.
 
    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
    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
@@ -2326,6 +2410,7 @@ constrain_operands (strict)
          int offset = 0;
          int win = 0;
          int val;
          int offset = 0;
          int win = 0;
          int val;
+         int len;
 
          earlyclobber[opno] = 0;
 
 
          earlyclobber[opno] = 0;
 
@@ -2350,9 +2435,16 @@ constrain_operands (strict)
          if (*p == 0 || *p == ',')
            win = 1;
 
          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;
              case '?':  case '!': case '*':  case '%':
              case '=':  case '+':
                break;
@@ -2360,8 +2452,10 @@ constrain_operands (strict)
              case '#':
                /* Ignore rest of this alternative as far as
                   constraint checking is concerned.  */
              case '#':
                /* Ignore rest of this alternative as far as
                   constraint checking is concerned.  */
-               while (*p && *p != ',')
+               do
                  p++;
                  p++;
+               while (*p && *p != ',');
+               len = 0;
                break;
 
              case '&':
                break;
 
              case '&':
@@ -2383,7 +2477,7 @@ constrain_operands (strict)
                  char *end;
                  int match;
 
                  char *end;
                  int match;
 
-                 match = strtoul (p - 1, &end, 10);
+                 match = strtoul (p, &end, 10);
                  p = end;
 
                  if (strict < 0)
                  p = end;
 
                  if (strict < 0)
@@ -2418,6 +2512,7 @@ constrain_operands (strict)
                      funny_match[funny_match_index++].other = match;
                    }
                }
                      funny_match[funny_match_index++].other = match;
                    }
                }
+               len = 0;
                break;
 
              case 'p':
                break;
 
              case 'p':
@@ -2477,27 +2572,17 @@ constrain_operands (strict)
                break;
 
              case 'E':
                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':
              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
                  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;
 
                  win = 1;
                break;
 
@@ -2527,7 +2612,7 @@ constrain_operands (strict)
              case 'O':
              case 'P':
                if (GET_CODE (op) == CONST_INT
              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;
 
                  win = 1;
                break;
 
@@ -2558,7 +2643,8 @@ constrain_operands (strict)
                {
                  enum reg_class class;
 
                {
                  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
                  if (class != NO_REGS)
                    {
                      if (strict < 0
@@ -2570,13 +2656,36 @@ constrain_operands (strict)
                              && reg_fits_class_p (op, class, offset, mode)))
                        win = 1;
                    }
                              && 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;
                    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;
                }
              }
 #endif
                  break;
                }
              }
+         while (p += len, c);
 
          constraints[opno] = p;
          /* If this operand did not win somehow,
 
          constraints[opno] = p;
          /* If this operand did not win somehow,
@@ -2689,11 +2798,7 @@ split_insn (insn)
          allocation, and there are unlikely to be very many
          nops then anyways.  */
       if (reload_completed)
          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;
-       }
+       delete_insn_and_edges (insn);
     }
   else
     {
     }
   else
     {
@@ -2709,7 +2814,7 @@ split_insn (insn)
          NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
 
          /* ??? Coddle to md files that generate subregs in post-
          NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
 
          /* ??? Coddle to md files that generate subregs in post-
-            reload splitters instead of computing the proper 
+            reload splitters instead of computing the proper
             hard register.  */
          if (reload_completed && first != last)
            {
             hard register.  */
          if (reload_completed && first != last)
            {
@@ -2735,25 +2840,26 @@ split_all_insns (upd_life)
      int upd_life;
 {
   sbitmap blocks;
      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);
   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;
       rtx insn, next;
+      bool finish = false;
 
 
-      for (insn = bb->head; insn ; insn = next)
+      for (insn = bb->head; !finish ; insn = next)
        {
          rtx last;
 
          /* Can't use `next_real_insn' because that might go across
             CODE_LABELS and short-out basic blocks.  */
          next = NEXT_INSN (insn);
        {
          rtx last;
 
          /* Can't use `next_real_insn' because that might go across
             CODE_LABELS and short-out basic blocks.  */
          next = NEXT_INSN (insn);
+         finish = (insn == bb->end);
          last = split_insn (insn);
          if (last)
            {
          last = split_insn (insn);
          if (last)
            {
@@ -2763,29 +2869,27 @@ split_all_insns (upd_life)
 
              while (GET_CODE (last) == BARRIER)
                last = PREV_INSN (last);
 
              while (GET_CODE (last) == BARRIER)
                last = PREV_INSN (last);
-             SET_BIT (blocks, i);
-             changed = 1;
+             SET_BIT (blocks, bb->index);
+             changed = true;
              insn = last;
            }
              insn = last;
            }
-
-         if (insn == bb->end)
-           break;
        }
        }
-
-      if (insn == NULL)
-       abort ();
     }
 
   if (changed)
     {
     }
 
   if (changed)
     {
+      int old_last_basic_block = last_basic_block;
+
       find_many_sub_basic_blocks (blocks);
       find_many_sub_basic_blocks (blocks);
+
+      if (old_last_basic_block != last_basic_block && upd_life)
+       blocks = sbitmap_resize (blocks, last_basic_block, 1);
     }
 
   if (changed && upd_life)
     }
 
   if (changed && upd_life)
-    {
-      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
 #ifdef ENABLE_CHECKING
   verify_flow_info ();
 #endif
@@ -2793,8 +2897,8 @@ split_all_insns (upd_life)
   sbitmap_free (blocks);
 }
 
   sbitmap_free (blocks);
 }
 
-/* Same as split_all_insns, but do not expect CFG to be available. 
-   Used by machine depedent reorg passes.  */
+/* 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
 split_all_insns_noflow ()
@@ -2942,7 +3046,7 @@ peep2_find_free_register (from, to, class_str, mode, reg_set)
     }
 
   class = (class_str[0] == 'r' ? GENERAL_REGS
     }
 
   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++)
     {
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
@@ -3012,11 +3116,14 @@ peephole2_optimize (dump_file)
   regset_head rs_heads[MAX_INSNS_PER_PEEP2 + 2];
   rtx insn, prev;
   regset live;
   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;
 #ifdef HAVE_conditional_execution
   sbitmap blocks;
-  int changed;
+  bool changed;
 #endif
 #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)
 
   /* Initialize the regsets we're going to use.  */
   for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
@@ -3024,16 +3131,15 @@ peephole2_optimize (dump_file)
   live = INITIALIZE_REG_SET (rs_heads[i]);
 
 #ifdef HAVE_conditional_execution
   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);
   sbitmap_zero (blocks);
-  changed = 0;
+  changed = false;
 #else
   count_or_remove_death_notes (NULL, 1);
 #endif
 
 #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.  */
       struct propagate_block_info *pbi;
 
       /* Indicate that all slots except the last holds invalid data.  */
@@ -3059,8 +3165,10 @@ peephole2_optimize (dump_file)
          prev = PREV_INSN (insn);
          if (INSN_P (insn))
            {
          prev = PREV_INSN (insn);
          if (INSN_P (insn))
            {
-             rtx try;
+             rtx try, before_try, x;
              int match_len;
              int match_len;
+             rtx note;
+             bool was_call = false;
 
              /* Record this insn.  */
              if (--peep2_current < 0)
 
              /* Record this insn.  */
              if (--peep2_current < 0)
@@ -3078,7 +3186,7 @@ peephole2_optimize (dump_file)
                     cfg-related call notes.  */
                  for (i = 0; i <= match_len; ++i)
                    {
                     cfg-related call notes.  */
                  for (i = 0; i <= match_len; ++i)
                    {
-                     int j, k;
+                     int j;
                      rtx old_insn, new_insn, note;
 
                      j = i + peep2_current;
                      rtx old_insn, new_insn, note;
 
                      j = i + peep2_current;
@@ -3087,21 +3195,17 @@ peephole2_optimize (dump_file)
                      old_insn = peep2_insn_data[j].insn;
                      if (GET_CODE (old_insn) != CALL_INSN)
                        continue;
                      old_insn = peep2_insn_data[j].insn;
                      if (GET_CODE (old_insn) != CALL_INSN)
                        continue;
+                     was_call = true;
 
 
-                     new_insn = NULL_RTX;
-                     if (GET_CODE (try) == SEQUENCE)
-                       for (k = XVECLEN (try, 0) - 1; k >= 0; k--)
-                         {
-                           rtx x = XVECEXP (try, 0, k);
-                           if (GET_CODE (x) == CALL_INSN)
-                             {
-                               new_insn = x;
-                               break;
-                             }
-                         }
-                     else if (GET_CODE (try) == CALL_INSN)
-                       new_insn = try;
-                     if (! new_insn)
+                     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)
                        abort ();
 
                      CALL_INSN_FUNCTION_USAGE (new_insn)
@@ -3112,7 +3216,6 @@ peephole2_optimize (dump_file)
                           note = XEXP (note, 1))
                        switch (REG_NOTE_KIND (note))
                          {
                           note = XEXP (note, 1))
                        switch (REG_NOTE_KIND (note))
                          {
-                         case REG_EH_REGION:
                          case REG_NORETURN:
                          case REG_SETJMP:
                          case REG_ALWAYS_RETURN:
                          case REG_NORETURN:
                          case REG_SETJMP:
                          case REG_ALWAYS_RETURN:
@@ -3120,6 +3223,8 @@ peephole2_optimize (dump_file)
                              = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
                                                   XEXP (note, 0),
                                                   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;
                          }
 
                            break;
                          }
 
@@ -3140,18 +3245,77 @@ peephole2_optimize (dump_file)
                  if (i >= MAX_INSNS_PER_PEEP2 + 1)
                    i -= MAX_INSNS_PER_PEEP2 + 1;
 
                  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.  */
                  /* Replace the old sequence with the new.  */
-                 try = emit_insn_after (try, peep2_insn_data[i].insn);
+                 try = emit_insn_after_scope (try, peep2_insn_data[i].insn,
+                                              INSN_SCOPE (peep2_insn_data[i].insn));
+                 before_try = PREV_INSN (insn);
                  delete_insn_chain (insn, peep2_insn_data[i].insn);
 
                  delete_insn_chain (insn, peep2_insn_data[i].insn);
 
+                 /* 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
                     live information so easily, since the conditional
                     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.  */
 #ifdef HAVE_conditional_execution
                  /* With conditional execution, we cannot back up the
                     live information so easily, since the conditional
                     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;
 
                  for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
                    peep2_insn_data[i].insn = NULL_RTX;
@@ -3164,25 +3328,35 @@ peephole2_optimize (dump_file)
                  COPY_REG_SET (live, peep2_insn_data[i].live_before);
 
                  /* Update life information for the new sequence.  */
                  COPY_REG_SET (live, peep2_insn_data[i].live_before);
 
                  /* Update life information for the new sequence.  */
+                 x = try;
                  do
                    {
                  do
                    {
-                     if (INSN_P (try))
+                     if (INSN_P (x))
                        {
                          if (--i < 0)
                            i = MAX_INSNS_PER_PEEP2;
                        {
                          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);
                        }
                          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
 
                  /* ??? 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;
+                     }
                }
            }
 
                }
            }
 
@@ -3197,10 +3371,135 @@ peephole2_optimize (dump_file)
     FREE_REG_SET (peep2_insn_data[i].live_before);
   FREE_REG_SET (live);
 
     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
 #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 */
   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 (out_insn, in_insn)
+     rtx out_insn, 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 (out_insn, in_insn)
+     rtx out_insn, 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;
+}