OSDN Git Service

* configure.in (case $THREADS): Add *-*-freebsd* configuration.
[pf3gnuchains/gcc-fork.git] / gcc / recog.c
index 9492180..a23f991 100644 (file)
@@ -1,23 +1,23 @@
 /* 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 Free Software Foundation, Inc.
+   1999, 2000, 2001 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
 
 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 "config.h"
@@ -26,17 +26,17 @@ Boston, MA 02111-1307, USA.  */
 #include "tm_p.h"
 #include "insn-config.h"
 #include "insn-attr.h"
 #include "tm_p.h"
 #include "insn-config.h"
 #include "insn-attr.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
 #include "hard-reg-set.h"
 #include "recog.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "recog.h"
 #include "regs.h"
+#include "expr.h"
 #include "function.h"
 #include "flags.h"
 #include "real.h"
 #include "toplev.h"
 #include "basic-block.h"
 #include "output.h"
 #include "function.h"
 #include "flags.h"
 #include "real.h"
 #include "toplev.h"
 #include "basic-block.h"
 #include "output.h"
+#include "reload.h"
 
 #ifndef STACK_PUSH_CODE
 #ifdef STACK_GROWS_DOWNWARD
 
 #ifndef STACK_PUSH_CODE
 #ifdef STACK_GROWS_DOWNWARD
@@ -56,8 +56,8 @@ Boston, MA 02111-1307, USA.  */
 
 static void validate_replace_rtx_1     PARAMS ((rtx *, rtx, rtx, rtx));
 static rtx *find_single_use_1          PARAMS ((rtx, rtx *));
 
 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 int insn_invalid_p              PARAMS ((rtx));
+static void validate_replace_src_1     PARAMS ((rtx *, void *));
+static rtx split_insn                  PARAMS ((rtx));
 
 /* Nonzero means allow operands to be volatile.
    This should be 0 if you are generating rtl, such as if you are calling
 
 /* Nonzero means allow operands to be volatile.
    This should be 0 if you are generating rtl, such as if you are calling
@@ -116,7 +116,7 @@ recog_memoized_1 (insn)
      rtx insn;
 {
   if (INSN_CODE (insn) < 0)
      rtx insn;
 {
   if (INSN_CODE (insn) < 0)
-    INSN_CODE (insn) = recog (PATTERN (insn), insn, NULL_PTR);
+    INSN_CODE (insn) = recog (PATTERN (insn), insn, 0);
   return INSN_CODE (insn);
 }
 \f
   return INSN_CODE (insn);
 }
 \f
@@ -150,7 +150,7 @@ check_asm_operands (x)
   operands = (rtx *) alloca (noperands * sizeof (rtx));
   constraints = (const char **) alloca (noperands * sizeof (char *));
 
   operands = (rtx *) alloca (noperands * sizeof (rtx));
   constraints = (const char **) alloca (noperands * sizeof (char *));
 
-  decode_asm_operands (x, operands, NULL_PTR, constraints, NULL_PTR);
+  decode_asm_operands (x, operands, NULL, constraints, NULL);
 
   for (i = 0; i < noperands; i++)
     {
 
   for (i = 0; i < noperands; i++)
     {
@@ -182,7 +182,7 @@ static int changes_allocated;
 
 static int num_changes = 0;
 
 
 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.
 
    at which NEW will be placed.  If OBJECT is zero, no validation is done,
    the change is simply made.
 
@@ -258,18 +258,43 @@ validate_change (object, loc, new, in_group)
 /* This subroutine of apply_change_group verifies whether the changes to INSN
    were valid; i.e. whether INSN can still be recognized.  */
 
 /* This subroutine of apply_change_group verifies whether the changes to INSN
    were valid; i.e. whether INSN can still be recognized.  */
 
-static int
+int
 insn_invalid_p (insn)
      rtx insn;
 {
 insn_invalid_p (insn)
      rtx insn;
 {
-  int icode = recog_memoized (insn);
+  rtx pat = PATTERN (insn);
+  int num_clobbers = 0;
+  /* If we are before reload and the pattern is a SET, see if we can add
+     clobbers.  */
+  int icode = recog (pat, insn,
+                    (GET_CODE (pat) == SET
+                     && ! reload_completed && ! reload_in_progress)
+                    ? &num_clobbers : 0);
   int is_asm = icode < 0 && asm_noperands (PATTERN (insn)) >= 0;
 
   int is_asm = icode < 0 && asm_noperands (PATTERN (insn)) >= 0;
 
-  if (is_asm && ! check_asm_operands (PATTERN (insn)))
-    return 1;
-  if (! is_asm && icode < 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)))
+      || (!is_asm && icode < 0))
     return 1;
 
     return 1;
 
+  /* If we have to add CLOBBERs, fail if we have to add ones that reference
+     hard registers since our callers can't know if they are live or not.
+     Otherwise, add them.  */
+  if (num_clobbers > 0)
+    {
+      rtx newpat;
+
+      if (added_clobbers_hard_reg_p (icode))
+       return 1;
+
+      newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_clobbers + 1));
+      XVECEXP (newpat, 0, 0) = pat;
+      add_clobbers (newpat, icode);
+      PATTERN (insn) = pat = newpat;
+    }
+
   /* After reload, verify that all constraints are satisfied.  */
   if (reload_completed)
     {
   /* After reload, verify that all constraints are satisfied.  */
   if (reload_completed)
     {
@@ -279,6 +304,7 @@ insn_invalid_p (insn)
        return 1;
     }
 
        return 1;
     }
 
+  INSN_CODE (insn) = icode;
   return 0;
 }
 
   return 0;
 }
 
@@ -289,6 +315,7 @@ int
 apply_change_group ()
 {
   int i;
 apply_change_group ()
 {
   int i;
+  rtx last_validated = NULL_RTX;
 
   /* The changes have been applied and all INSN_CODEs have been reset to force
      rerecognition.
 
   /* The changes have been applied and all INSN_CODEs have been reset to force
      rerecognition.
@@ -303,7 +330,9 @@ apply_change_group ()
     {
       rtx object = changes[i].object;
 
     {
       rtx object = changes[i].object;
 
-      if (object == 0)
+      /* 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;
 
       if (GET_CODE (object) == MEM)
        continue;
 
       if (GET_CODE (object) == MEM)
@@ -324,32 +353,33 @@ apply_change_group ()
              && GET_CODE (XVECEXP (pat, 0, XVECLEN (pat, 0) - 1)) == CLOBBER
              && asm_noperands (PATTERN (object)) < 0)
            {
              && 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, 
-                                        gen_rtvec (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);
-            }
+             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.  */
          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.  */
@@ -357,6 +387,7 @@ apply_change_group ()
          else
            break;
        }
          else
            break;
        }
+      last_validated = object;
     }
 
   if (i == num_changes)
     }
 
   if (i == num_changes)
@@ -371,7 +402,7 @@ 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 ()
 
 int
 num_validated_changes ()
@@ -406,14 +437,22 @@ validate_replace_rtx_1 (loc, from, to, object)
      rtx *loc;
      rtx from, to, object;
 {
      rtx *loc;
      rtx from, to, 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 rtx_code code;
+  enum machine_mode op0_mode = VOIDmode;
+  int prev_changes = num_changes;
+  rtx new;
 
   if (!x)
     return;
 
   if (!x)
     return;
+
   code = GET_CODE (x);
   code = GET_CODE (x);
+  fmt = GET_RTX_FORMAT (code);
+  if (fmt[0] == 'e')
+    op0_mode = GET_MODE (XEXP (x, 0));
+
   /* X matches FROM if it is the same rtx or they are both referring to the
      same register in the same mode.  Avoid calling rtx_equal_p unless the
      operands look similar.  */
   /* X matches FROM if it is the same rtx or they are both referring to the
      same register in the same mode.  Avoid calling rtx_equal_p unless the
      operands look similar.  */
@@ -429,189 +468,117 @@ validate_replace_rtx_1 (loc, from, to, object)
       return;
     }
 
       return;
     }
 
-  /* For commutative or comparison operations, try replacing each argument
-     separately and seeing if we made any changes.  If so, put a constant
-     argument last.*/
-  if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == 'c')
-    {
-      int prev_changes = num_changes;
+  /* Call ourself recursively to perform the replacements.  */
 
 
-      validate_replace_rtx_1 (&XEXP (x, 0), from, to, object);
-      validate_replace_rtx_1 (&XEXP (x, 1), from, to, object);
-      if (prev_changes != num_changes && CONSTANT_P (XEXP (x, 0)))
-       {
-         validate_change (object, loc,
-                          gen_rtx_fmt_ee (GET_RTX_CLASS (code) == 'c' ? code
-                                          : swap_condition (code),
-                                          GET_MODE (x), XEXP (x, 1),
-                                          XEXP (x, 0)),
-                          1);
-         x = *loc;
-         code = GET_CODE (x);
-       }
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       validate_replace_rtx_1 (&XEXP (x, i), from, to, object);
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object);
     }
 
     }
 
-  /* Note that if CODE's RTX_CLASS is "c" or "<" we will have already
-     done the substitution, otherwise we won't.  */
+  /* If we didn't substitute, there is nothing more to do.  */
+  if (num_changes == prev_changes)
+    return;
+
+  /* Allow substituted expression to have different mode.  This is used by
+     regmove to change mode of pseudo register.  */
+  if (fmt[0] == 'e' && GET_MODE (XEXP (x, 0)) != VOIDmode)
+    op0_mode = GET_MODE (XEXP (x, 0));
+
+  /* Do changes needed to keep rtx consistent.  Don't do any other
+     simplifications, as it is not our job.  */
+
+  if ((GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == 'c')
+      && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
+    {
+      validate_change (object, loc,
+                      gen_rtx_fmt_ee (GET_RTX_CLASS (code) == 'c' ? code
+                                      : swap_condition (code),
+                                      GET_MODE (x), XEXP (x, 1),
+                                      XEXP (x, 0)), 1);
+      x = *loc;
+      code = GET_CODE (x);
+    }
 
   switch (code)
     {
     case PLUS:
       /* If we have a PLUS whose second operand is now a CONST_INT, use
 
   switch (code)
     {
     case PLUS:
       /* If we have a PLUS whose second operand is now a CONST_INT, use
-        plus_constant to try to simplify it.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)
-       validate_change (object, loc, plus_constant (XEXP (x, 0), INTVAL (to)),
-                        1);
-      return;
-
+         plus_constant 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)
+       validate_change (object, loc,
+                        plus_constant (XEXP (x, 0), INTVAL (XEXP (x, 1))), 1);
+      break;
     case MINUS:
     case MINUS:
-      if (GET_CODE (to) == CONST_INT && XEXP (x, 1) == from)
-       {
-         validate_change (object, loc,
-                          plus_constant (XEXP (x, 0), - INTVAL (to)),
-                          1);
-         return;
-       }
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         || GET_CODE (XEXP (x, 1)) == CONST_DOUBLE)
+       validate_change (object, loc,
+                        simplify_gen_binary
+                        (PLUS, GET_MODE (x), XEXP (x, 0),
+                         simplify_gen_unary (NEG,
+                                             GET_MODE (x), XEXP (x, 1),
+                                             GET_MODE (x))), 1);
       break;
       break;
-      
     case ZERO_EXTEND:
     case SIGN_EXTEND:
     case ZERO_EXTEND:
     case SIGN_EXTEND:
-      /* In these cases, the operation to be performed depends on the mode
-        of the operand.  If we are replacing the operand with a VOIDmode
-        constant, we lose the information.  So try to simplify the operation
-        in that case.  If it fails, substitute in something that we know
-        won't be recognized.  */
-      if (GET_MODE (to) == VOIDmode
-         && rtx_equal_p (XEXP (x, 0), from))
+      if (GET_MODE (XEXP (x, 0)) == VOIDmode)
        {
        {
-         rtx new = simplify_unary_operation (code, GET_MODE (x), to,
-                                             GET_MODE (from));
-         if (new == 0)
+         new = simplify_gen_unary (code, GET_MODE (x), XEXP (x, 0),
+                                   op0_mode);
+         /* If any of the above failed, substitute in something that
+            we know won't be recognized.  */
+         if (!new)
            new = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
            new = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
-
          validate_change (object, loc, new, 1);
          validate_change (object, loc, new, 1);
-         return;
        }
       break;
        }
       break;
-       
     case SUBREG:
     case SUBREG:
-      /* In case we are replacing by constant, attempt to simplify it to non-SUBREG
-         expression.  We can't do this later, since the information about inner mode
-         may be lost.  */
-      if (CONSTANT_P (to) && rtx_equal_p (SUBREG_REG (x), from))
-        {
-         if (GET_MODE_SIZE (GET_MODE (x)) == UNITS_PER_WORD
-             && GET_MODE_SIZE (GET_MODE (from)) > UNITS_PER_WORD
-             && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
-           {
-             rtx temp = operand_subword (to, SUBREG_WORD (x),
-                                         0, GET_MODE (from));
-             if (temp)
-               {
-                 validate_change (object, loc, temp, 1);
-                 return;
-               }
-           }
-         if (subreg_lowpart_p (x))
-           {
-             rtx new =  gen_lowpart_if_possible (GET_MODE (x), to);
-             if (new)
-               {
-                 validate_change (object, loc, new, 1);
-                 return;
-               }
-           }
-
-         /* A paradoxical SUBREG of a VOIDmode constant is the same constant,
-            since we are saying that the high bits don't matter.  */
-         if (GET_MODE (to) == VOIDmode
-             && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (from)))
-           {
-             validate_change (object, loc, to, 1);
-             return;
-           }
-        }
-
-      /* Changing mode twice with SUBREG => just change it once,
-        or not at all if changing back to starting mode.  */
-      if (GET_CODE (to) == SUBREG
-         && rtx_equal_p (SUBREG_REG (x), from))
-       {
-         if (GET_MODE (x) == GET_MODE (SUBREG_REG (to))
-             && SUBREG_WORD (x) == 0 && SUBREG_WORD (to) == 0)
-           {
-             validate_change (object, loc, SUBREG_REG (to), 1);
-             return;
-           }
-
-         validate_change (object, loc,
-                          gen_rtx_SUBREG (GET_MODE (x), SUBREG_REG (to),
-                                          SUBREG_WORD (x) + SUBREG_WORD (to)), 1);
-         return;
-       }
-
-      /* If we have a SUBREG of a register that we are replacing and we are
-        replacing it with a MEM, make a new MEM and try replacing the
-        SUBREG with it.  Don't do this if the MEM has a mode-dependent address
-        or if we would be widening it.  */
-
-      if (GET_CODE (from) == REG
-         && GET_CODE (to) == MEM
-         && rtx_equal_p (SUBREG_REG (x), from)
-         && ! mode_dependent_address_p (XEXP (to, 0))
-         && ! MEM_VOLATILE_P (to)
-         && GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (GET_MODE (to)))
-       {
-         int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
-         enum machine_mode mode = GET_MODE (x);
-         rtx new;
-
-         if (BYTES_BIG_ENDIAN)
-           offset += (MIN (UNITS_PER_WORD,
-                           GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-                      - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
-
-         new = gen_rtx_MEM (mode, plus_constant (XEXP (to, 0), offset));
-         MEM_COPY_ATTRIBUTES (new, to);
-         validate_change (object, loc, new, 1);
-         return;
-       }
+      /* All subregs possible to simplify should be simplified.  */
+      new = simplify_subreg (GET_MODE (x), SUBREG_REG (x), op0_mode,
+                            SUBREG_BYTE (x));
+
+      /* 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)
+       validate_change (object, loc, new, 1);
       break;
       break;
-
     case ZERO_EXTRACT:
     case SIGN_EXTRACT:
       /* If we are replacing a register with memory, try to change the memory
     case ZERO_EXTRACT:
     case SIGN_EXTRACT:
       /* If we are replacing a register with memory, try to change the memory
-        to be the mode required for memory in extract operations (this isn't
-        likely to be an insertion operation; if it was, nothing bad will
-        happen, we might just fail in some cases).  */
+         to be the mode required for memory in extract operations (this isn't
+         likely to be an insertion operation; if it was, nothing bad will
+         happen, we might just fail in some cases).  */
 
 
-      if (GET_CODE (from) == REG && GET_CODE (to) == MEM
-         && rtx_equal_p (XEXP (x, 0), from)
+      if (GET_CODE (XEXP (x, 0)) == MEM
          && GET_CODE (XEXP (x, 1)) == CONST_INT
          && GET_CODE (XEXP (x, 2)) == CONST_INT
          && GET_CODE (XEXP (x, 1)) == CONST_INT
          && GET_CODE (XEXP (x, 2)) == CONST_INT
-         && ! mode_dependent_address_p (XEXP (to, 0))
-         && ! MEM_VOLATILE_P (to))
+         && !mode_dependent_address_p (XEXP (XEXP (x, 0), 0))
+         && !MEM_VOLATILE_P (XEXP (x, 0)))
        {
          enum machine_mode wanted_mode = VOIDmode;
        {
          enum machine_mode wanted_mode = VOIDmode;
-         enum machine_mode is_mode = GET_MODE (to);
+         enum machine_mode is_mode = GET_MODE (XEXP (x, 0));
          int pos = INTVAL (XEXP (x, 2));
 
          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
 
          /* If we have a narrower mode, we can do something.  */
          if (wanted_mode != VOIDmode
@@ -620,17 +587,16 @@ validate_replace_rtx_1 (loc, from, to, object)
              int offset = pos / BITS_PER_UNIT;
              rtx newmem;
 
              int offset = pos / BITS_PER_UNIT;
              rtx newmem;
 
-                 /* If the bytes and bits are counted differently, we
-                    must adjust the offset.  */
+             /* If the bytes and bits are counted differently, we
+                must adjust the offset.  */
              if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN)
              if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN)
-               offset = (GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (wanted_mode)
-                         - offset);
+               offset =
+                 (GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (wanted_mode) -
+                  offset);
 
              pos %= GET_MODE_BITSIZE (wanted_mode);
 
 
              pos %= GET_MODE_BITSIZE (wanted_mode);
 
-             newmem = gen_rtx_MEM (wanted_mode,
-                                   plus_constant (XEXP (to, 0), offset));
-             MEM_COPY_ATTRIBUTES (newmem, to);
+             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);
 
              validate_change (object, &XEXP (x, 2), GEN_INT (pos), 1);
              validate_change (object, &XEXP (x, 0), newmem, 1);
@@ -638,25 +604,10 @@ validate_replace_rtx_1 (loc, from, to, object)
        }
 
       break;
        }
 
       break;
-      
+
     default:
       break;
     }
     default:
       break;
     }
-      
-  /* For commutative or comparison operations we've already performed
-     replacements.  Don't try to perform them again.  */
-  if (GET_RTX_CLASS (code) != '<' && GET_RTX_CLASS (code) != 'c')
-    {
-      fmt = GET_RTX_FORMAT (code);
-      for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-        {
-          if (fmt[i] == 'e')
-            validate_replace_rtx_1 (&XEXP (x, i), from, to, object);
-          else if (fmt[i] == 'E')
-            for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-              validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object);
-        }
-    }
 }
 
 /* Try replacing every occurrence of FROM in subexpression LOC of INSN
 }
 
 /* Try replacing every occurrence of FROM in subexpression LOC of INSN
@@ -682,8 +633,7 @@ validate_replace_rtx (from, to, insn)
   return apply_change_group ();
 }
 
   return apply_change_group ();
 }
 
-/* Try replacing every occurrence of FROM in INSN with TO.  After all
-   changes have been made, validate by seeing if INSN is still valid.  */
+/* Try replacing every occurrence of FROM in INSN with TO.  */
 
 void
 validate_replace_rtx_group (from, to, insn)
 
 void
 validate_replace_rtx_group (from, to, insn)
@@ -692,6 +642,25 @@ validate_replace_rtx_group (from, to, insn)
   validate_replace_rtx_1 (&PATTERN (insn), from, to, insn);
 }
 
   validate_replace_rtx_1 (&PATTERN (insn), from, to, insn);
 }
 
+/* Function called by note_uses to replace used subexpressions.  */
+struct validate_replace_src_data
+{
+  rtx from;                    /* Old RTX */
+  rtx to;                      /* New RTX */
+  rtx insn;                    /* Insn in which substitution is occurring.  */
+};
+
+static void
+validate_replace_src_1 (x, data)
+     rtx *x;
+     void *data;
+{
+  struct validate_replace_src_data *d
+    = (struct validate_replace_src_data *) data;
+
+  validate_replace_rtx_1 (x, d->from, d->to, d->insn);
+}
+
 /* 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.  */
 /* 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.  */
@@ -700,14 +669,12 @@ int
 validate_replace_src (from, to, insn)
      rtx from, to, insn;
 {
 validate_replace_src (from, to, insn)
      rtx from, to, insn;
 {
-  if ((GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
-      || GET_CODE (PATTERN (insn)) != SET)
-    abort ();
+  struct validate_replace_src_data d;
 
 
-  validate_replace_rtx_1 (&SET_SRC (PATTERN (insn)), from, to, insn);
-  if (GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
-    validate_replace_rtx_1 (&XEXP (SET_DEST (PATTERN (insn)), 0),
-                           from, to, insn);
+  d.from = from;
+  d.to = to;
+  d.insn = insn;
+  note_uses (&PATTERN (insn), validate_replace_src_1, &d);
   return apply_change_group ();
 }
 \f
   return apply_change_group ();
 }
 \f
@@ -720,7 +687,7 @@ int
 next_insn_tests_no_inequality (insn)
      rtx insn;
 {
 next_insn_tests_no_inequality (insn)
      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)
 
   /* If there is no next insn, we have to take the conservative choice.  */
   if (next == 0)
@@ -740,7 +707,7 @@ int
 next_insns_test_no_inequality (insn)
      rtx insn;
 {
 next_insns_test_no_inequality (insn)
      rtx insn;
 {
-  register rtx next = NEXT_INSN (insn);
+  rtx next = NEXT_INSN (insn);
 
   for (; next != 0; next = NEXT_INSN (next))
     {
 
   for (; next != 0; next = NEXT_INSN (next))
     {
@@ -946,11 +913,10 @@ find_single_use (dest, insn, ploc)
 
 int
 general_operand (op, mode)
 
 int
 general_operand (op, mode)
-     register rtx op;
+     rtx op;
      enum machine_mode mode;
 {
      enum machine_mode mode;
 {
-  register enum rtx_code code = GET_CODE (op);
-  int mode_altering_drug = 0;
+  enum rtx_code code = GET_CODE (op);
 
   if (mode == VOIDmode)
     mode = GET_MODE (op);
 
   if (mode == VOIDmode)
     mode = GET_MODE (op);
@@ -962,6 +928,10 @@ general_operand (op, mode)
       && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
     return 0;
 
       && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
     return 0;
 
+  if (GET_CODE (op) == CONST_INT
+      && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
+    return 0;
+
   if (CONSTANT_P (op))
     return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
             || mode == VOIDmode)
   if (CONSTANT_P (op))
     return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
             || mode == VOIDmode)
@@ -985,14 +955,18 @@ general_operand (op, mode)
          && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
        return 0;
 #endif
          && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
        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. 
+
+        ??? This is a kludge.  */
+      if (!reload_completed && SUBREG_BYTE (op) != 0
+         && GET_CODE (SUBREG_REG (op)) == MEM)
+        return 0;
 
       op = SUBREG_REG (op);
       code = GET_CODE (op);
 
       op = SUBREG_REG (op);
       code = GET_CODE (op);
-#if 0
-      /* No longer needed, since (SUBREG (MEM...))
-        will load the MEM into a reload reg in the MEM's own mode.  */
-      mode_altering_drug = 1;
-#endif
     }
 
   if (code == REG)
     }
 
   if (code == REG)
@@ -1002,7 +976,7 @@ general_operand (op, mode)
 
   if (code == MEM)
     {
 
   if (code == MEM)
     {
-      register rtx y = XEXP (op, 0);
+      rtx y = XEXP (op, 0);
 
       if (! volatile_ok && MEM_VOLATILE_P (op))
        return 0;
 
       if (! volatile_ok && MEM_VOLATILE_P (op))
        return 0;
@@ -1023,8 +997,6 @@ general_operand (op, mode)
   return 0;
 
  win:
   return 0;
 
  win:
-  if (mode_altering_drug)
-    return ! mode_dependent_address_p (XEXP (op, 0));
   return 1;
 }
 \f
   return 1;
 }
 \f
@@ -1036,7 +1008,7 @@ general_operand (op, mode)
 
 int
 address_operand (op, mode)
 
 int
 address_operand (op, mode)
-     register rtx op;
+     rtx op;
      enum machine_mode mode;
 {
   return memory_address_p (mode, op);
      enum machine_mode mode;
 {
   return memory_address_p (mode, op);
@@ -1058,7 +1030,7 @@ address_operand (op, mode)
 
 int
 register_operand (op, mode)
 
 int
 register_operand (op, mode)
-     register rtx op;
+     rtx op;
      enum machine_mode mode;
 {
   if (GET_MODE (op) != mode && mode != VOIDmode)
      enum machine_mode mode;
 {
   if (GET_MODE (op) != mode && mode != VOIDmode)
@@ -1091,7 +1063,7 @@ register_operand (op, mode)
     }
 
   /* If we have an ADDRESSOF, consider it valid since it will be
     }
 
   /* 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;
 
   if (GET_CODE (op) == ADDRESSOF)
     return 1;
 
@@ -1117,7 +1089,7 @@ pmode_register_operand (op, mode)
 
 int
 scratch_operand (op, mode)
 
 int
 scratch_operand (op, mode)
-     register rtx op;
+     rtx op;
      enum machine_mode mode;
 {
   if (GET_MODE (op) != mode && mode != VOIDmode)
      enum machine_mode mode;
 {
   if (GET_MODE (op) != mode && mode != VOIDmode)
@@ -1135,7 +1107,7 @@ scratch_operand (op, mode)
 
 int
 immediate_operand (op, mode)
 
 int
 immediate_operand (op, mode)
-     register rtx op;
+     rtx op;
      enum machine_mode mode;
 {
   /* Don't accept CONST_INT or anything similar
      enum machine_mode mode;
 {
   /* Don't accept CONST_INT or anything similar
@@ -1145,6 +1117,10 @@ immediate_operand (op, mode)
       && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
     return 0;
 
       && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
     return 0;
 
+  if (GET_CODE (op) == CONST_INT
+      && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
+    return 0;
+
   /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and
      result in 0/1.  It seems a safe assumption that this is
      in range for everyone.  */
   /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and
      result in 0/1.  It seems a safe assumption that this is
      in range for everyone.  */
@@ -1164,10 +1140,17 @@ immediate_operand (op, mode)
 
 int
 const_int_operand (op, mode)
 
 int
 const_int_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+     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
 }
 
 /* Returns 1 if OP is an operand that is a constant integer or constant
@@ -1175,7 +1158,7 @@ const_int_operand (op, mode)
 
 int
 const_double_operand (op, mode)
 
 int
 const_double_operand (op, mode)
-     register rtx op;
+     rtx op;
      enum machine_mode mode;
 {
   /* Don't accept CONST_INT or anything similar
      enum machine_mode mode;
 {
   /* Don't accept CONST_INT or anything similar
@@ -1194,7 +1177,7 @@ const_double_operand (op, mode)
 
 int
 nonimmediate_operand (op, mode)
 
 int
 nonimmediate_operand (op, mode)
-     register rtx op;
+     rtx op;
      enum machine_mode mode;
 {
   return (general_operand (op, mode) && ! CONSTANT_P (op));
      enum machine_mode mode;
 {
   return (general_operand (op, mode) && ! CONSTANT_P (op));
@@ -1204,7 +1187,7 @@ nonimmediate_operand (op, mode)
 
 int
 nonmemory_operand (op, mode)
 
 int
 nonmemory_operand (op, mode)
-     register rtx op;
+     rtx op;
      enum machine_mode mode;
 {
   if (CONSTANT_P (op))
      enum machine_mode mode;
 {
   if (CONSTANT_P (op))
@@ -1216,8 +1199,12 @@ nonmemory_operand (op, mode)
          && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
        return 0;
 
          && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
        return 0;
 
+      if (GET_CODE (op) == CONST_INT
+         && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
+       return 0;
+
       return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
       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
 #ifdef LEGITIMATE_PIC_OPERAND_P
              && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
 #endif
@@ -1258,6 +1245,12 @@ push_operand (op, mode)
      rtx op;
      enum machine_mode mode;
 {
      rtx op;
      enum machine_mode mode;
 {
+  unsigned int rounded_size = GET_MODE_SIZE (mode);
+
+#ifdef PUSH_ROUNDING
+  rounded_size = PUSH_ROUNDING (rounded_size);
+#endif
+
   if (GET_CODE (op) != MEM)
     return 0;
 
   if (GET_CODE (op) != MEM)
     return 0;
 
@@ -1266,8 +1259,25 @@ push_operand (op, mode)
 
   op = XEXP (op, 0);
 
 
   op = XEXP (op, 0);
 
-  if (GET_CODE (op) != STACK_PUSH_CODE)
-    return 0;
+  if (rounded_size == GET_MODE_SIZE (mode))
+    {
+      if (GET_CODE (op) != STACK_PUSH_CODE)
+       return 0;
+    }
+  else
+    {
+      if (GET_CODE (op) != PRE_MODIFY
+         || GET_CODE (XEXP (op, 1)) != PLUS
+         || XEXP (XEXP (op, 1), 0) != XEXP (op, 0)
+         || GET_CODE (XEXP (XEXP (op, 1), 1)) != CONST_INT
+#ifdef STACK_GROWS_DOWNWARD
+         || INTVAL (XEXP (XEXP (op, 1), 1)) != - (int) rounded_size
+#else
+         || INTVAL (XEXP (XEXP (op, 1), 1)) != rounded_size
+#endif
+         )
+       return 0;
+    }
 
   return XEXP (op, 0) == stack_pointer_rtx;
 }
 
   return XEXP (op, 0) == stack_pointer_rtx;
 }
@@ -1302,7 +1312,7 @@ pop_operand (op, mode)
 int
 memory_address_p (mode, addr)
      enum machine_mode mode ATTRIBUTE_UNUSED;
 int
 memory_address_p (mode, addr)
      enum machine_mode mode ATTRIBUTE_UNUSED;
-     register rtx addr;
+     rtx addr;
 {
   if (GET_CODE (addr) == ADDRESSOF)
     return 1;
 {
   if (GET_CODE (addr) == ADDRESSOF)
     return 1;
@@ -1322,7 +1332,7 @@ memory_address_p (mode, addr)
 
 int
 memory_operand (op, mode)
 
 int
 memory_operand (op, mode)
-     register rtx op;
+     rtx op;
      enum machine_mode mode;
 {
   rtx inner;
      enum machine_mode mode;
 {
   rtx inner;
@@ -1347,20 +1357,16 @@ memory_operand (op, mode)
 
 int
 indirect_operand (op, mode)
 
 int
 indirect_operand (op, mode)
-     register rtx op;
+     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)
     {
      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_WORD (op) * UNITS_PER_WORD;
+      int offset = SUBREG_BYTE (op);
       rtx inner = SUBREG_REG (op);
 
       rtx inner = SUBREG_REG (op);
 
-      if (BYTES_BIG_ENDIAN)
-       offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (op)))
-                  - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (inner))));
-
       if (mode != VOIDmode && GET_MODE (op) != mode)
        return 0;
 
       if (mode != VOIDmode && GET_MODE (op) != mode)
        return 0;
 
@@ -1386,7 +1392,7 @@ indirect_operand (op, mode)
 
 int
 comparison_operator (op, mode)
 
 int
 comparison_operator (op, mode)
-    register rtx op;
+    rtx op;
     enum machine_mode mode;
 {
   return ((mode == VOIDmode || GET_MODE (op) == mode)
     enum machine_mode mode;
 {
   return ((mode == VOIDmode || GET_MODE (op) == mode)
@@ -1490,7 +1496,7 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes)
      const char **constraints;
      enum machine_mode *modes;
 {
      const char **constraints;
      enum machine_mode *modes;
 {
-  register int i;
+  int i;
   int noperands;
   const char *template = 0;
 
   int noperands;
   const char *template = 0;
 
@@ -1651,6 +1657,8 @@ 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 (ISDIGIT (*constraint))
+           constraint++;
          result = -1;
          break;
 
          result = -1;
          break;
 
@@ -1818,12 +1826,12 @@ asm_operand_ok (op, constraint)
    return the location (type rtx *) of the pointer to that constant term.
    Otherwise, return a null pointer.  */
 
    return the location (type rtx *) of the pointer to that constant term.
    Otherwise, return a null pointer.  */
 
-static rtx *
+rtx *
 find_constant_term_loc (p)
      rtx *p;
 {
 find_constant_term_loc (p)
      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.  */
 
 
   /* If *P IS such a constant term, P is its location.  */
 
@@ -1905,10 +1913,10 @@ int
 offsettable_address_p (strictp, mode, y)
      int strictp;
      enum machine_mode mode;
 offsettable_address_p (strictp, mode, y)
      int strictp;
      enum machine_mode mode;
-     register rtx y;
+     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)) =
   rtx y1 = y;
   rtx *y2;
   int (*addressp) PARAMS ((enum machine_mode, rtx)) =
@@ -1955,9 +1963,13 @@ 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
   /* 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)
+    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.  */
 
   /* Use QImode because an odd displacement may be automatically invalid
      for any wider mode.  But it should be valid for a single byte.  */
@@ -1972,11 +1984,11 @@ offsettable_address_p (strictp, mode, y)
 
 int
 mode_dependent_address_p (addr)
 
 int
 mode_dependent_address_p (addr)
-  rtx addr ATTRIBUTE_UNUSED; /* Maybe used in GO_IF_MODE_DEPENDENT_ADDRESS. */
+  rtx addr ATTRIBUTE_UNUSED; /* Maybe used in GO_IF_MODE_DEPENDENT_ADDRESS.  */
 {
   GO_IF_MODE_DEPENDENT_ADDRESS (addr, win);
   return 0;
 {
   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;
 }
  win: ATTRIBUTE_UNUSED_LABEL
   return 1;
 }
@@ -2000,57 +2012,10 @@ mode_independent_operand (op, mode)
   addr = XEXP (op, 0);
   GO_IF_MODE_DEPENDENT_ADDRESS (addr, lose);
   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. */
+  /* Label `lose' might (not) be used via GO_IF_MODE_DEPENDENT_ADDRESS.  */
  lose: ATTRIBUTE_UNUSED_LABEL
   return 0;
 }
  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
 \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
@@ -2248,8 +2213,12 @@ preprocess_constraints ()
 
                case '0': case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
 
                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;
+                 {
+                   char *end;
+                   op_alt[j].matches = strtoul (p - 1, &end, 10);
+                   recog_op_alt[op_alt[j].matches][j].matched = i;
+                   p = end;
+                 }
                  break;
 
                case 'm':
                  break;
 
                case 'm':
@@ -2328,7 +2297,7 @@ constrain_operands (strict)
   const char *constraints[MAX_RECOG_OPERANDS];
   int matching_operands[MAX_RECOG_OPERANDS];
   int earlyclobber[MAX_RECOG_OPERANDS];
   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;
 
   struct funny_match funny_match[MAX_RECOG_OPERANDS];
   int funny_match_index;
@@ -2345,15 +2314,15 @@ constrain_operands (strict)
 
   do
     {
 
   do
     {
-      register int opno;
+      int opno;
       int lose = 0;
       funny_match_index = 0;
 
       for (opno = 0; opno < recog_data.n_operands; 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);
          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 offset = 0;
          int win = 0;
          int val;
@@ -2369,7 +2338,10 @@ constrain_operands (strict)
            {
              if (GET_CODE (SUBREG_REG (op)) == REG
                  && REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
            {
              if (GET_CODE (SUBREG_REG (op)) == REG
                  && REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
-               offset = SUBREG_WORD (op);
+               offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
+                                             GET_MODE (SUBREG_REG (op)),
+                                             SUBREG_BYTE (op),
+                                             GET_MODE (op));
              op = SUBREG_REG (op);
            }
 
              op = SUBREG_REG (op);
            }
 
@@ -2398,45 +2370,54 @@ constrain_operands (strict)
 
              case '0':  case '1':  case '2':  case '3':  case '4':
              case '5':  case '6':  case '7':  case '8':  case '9':
 
              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 - 1, &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;
+                   }
+               }
                break;
 
              case 'p':
                break;
 
              case 'p':
@@ -2665,16 +2646,16 @@ constrain_operands (strict)
 int
 reg_fits_class_p (operand, class, offset, mode)
      rtx operand;
 int
 reg_fits_class_p (operand, class, offset, mode)
      rtx operand;
-     register enum reg_class class;
+     enum reg_class class;
      int offset;
      enum machine_mode mode;
 {
      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))
     {
   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--)
       regno += offset;
       for (sr = HARD_REGNO_NREGS (regno, mode) - 1;
           sr > 0; sr--)
@@ -2687,6 +2668,66 @@ reg_fits_class_p (operand, class, offset, mode)
   return 0;
 }
 \f
   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 (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)
+       {
+         PUT_CODE (insn, NOTE);
+         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+         NOTE_SOURCE_FILE (insn) = 0;
+       }
+    }
+  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 in the function.  If UPD_LIFE, update life info after.  */
 
 void
@@ -2708,79 +2749,65 @@ split_all_insns (upd_life)
 
       for (insn = bb->head; insn ; insn = next)
        {
 
       for (insn = bb->head; insn ; 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);
 
          /* 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
-                  && rtx_equal_p (SET_SRC (set), SET_DEST (set)))
+         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;
-               }
-           }
-         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.  */
-                 first = NEXT_INSN (first);
-                 PUT_CODE (insn, NOTE);
-                 NOTE_SOURCE_FILE (insn) = 0;
-                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-
-                 if (insn == bb->end)
-                   {
-                     bb->end = last;
-                     break;
-                   }
-               }
+             /* 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, i);
+             changed = 1;
+             insn = last;
            }
 
          if (insn == bb->end)
            break;
        }
 
            }
 
          if (insn == bb->end)
            break;
        }
 
-      /* ??? 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)
+      if (insn == NULL)
        abort ();
     }
 
        abort ();
     }
 
+  if (changed)
+    {
+      find_many_sub_basic_blocks (blocks);
+    }
+
   if (changed && upd_life)
     {
   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);
     }
       count_or_remove_death_notes (blocks, 1);
       update_life_info (blocks, UPDATE_LIFE_LOCAL, PROP_DEATH_NOTES);
     }
+#ifdef ENABLE_CHECKING
+  verify_flow_info ();
+#endif
 
   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.  */
+
+void
+split_all_insns_noflow ()
+{
+  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
 \f
 #ifdef HAVE_peephole2
 struct peep2_insn_data
@@ -2976,7 +3003,7 @@ peep2_find_free_register (from, to, class_str, mode, reg_set)
   return NULL_RTX;
 }
 
   return NULL_RTX;
 }
 
-/* Perform the peephole2 optimization pass. */
+/* Perform the peephole2 optimization pass.  */
 
 void
 peephole2_optimize (dump_file)
 
 void
 peephole2_optimize (dump_file)
@@ -3022,9 +3049,9 @@ peephole2_optimize (dump_file)
       COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
 
 #ifdef HAVE_conditional_execution
       COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
 
 #ifdef HAVE_conditional_execution
-      pbi = init_propagate_block_info (bb, live, NULL, 0);
+      pbi = init_propagate_block_info (bb, live, NULL, NULL, 0);
 #else
 #else
-      pbi = init_propagate_block_info (bb, live, NULL, PROP_DEATH_NOTES);
+      pbi = init_propagate_block_info (bb, live, NULL, NULL, PROP_DEATH_NOTES);
 #endif
 
       for (insn = bb->end; ; insn = prev)
 #endif
 
       for (insn = bb->end; ; insn = prev)
@@ -3046,19 +3073,78 @@ peephole2_optimize (dump_file)
              try = peephole2_insns (PATTERN (insn), insn, &match_len);
              if (try != NULL)
                {
              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, k;
+                     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;
+
+                     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)
+                       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_EH_REGION:
+                         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;
 
                  /* Replace the old sequence with the new.  */
                  i = match_len + peep2_current;
                  if (i >= MAX_INSNS_PER_PEEP2 + 1)
                    i -= MAX_INSNS_PER_PEEP2 + 1;
 
                  /* Replace the old sequence with the new.  */
-                 flow_delete_insn_chain (insn, peep2_insn_data[i].insn);
-                 try = emit_insn_after (try, prev);
-
-                 /* 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);
+                 try = emit_insn_after (try, peep2_insn_data[i].insn);
+                 delete_insn_chain (insn, peep2_insn_data[i].insn);
 
 #ifdef HAVE_conditional_execution
                  /* With conditional execution, we cannot back up the
 
 #ifdef HAVE_conditional_execution
                  /* With conditional execution, we cannot back up the