OSDN Git Service

* regmove.c (STACK_GROWS_DOWNWARD): Don't boolean-ize.
[pf3gnuchains/gcc-fork.git] / gcc / regmove.c
index 1d6578f..416c950 100644 (file)
@@ -1,23 +1,23 @@
 /* Move registers around to reduce number of move instructions needed.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 /* This module looks for cases where matching constraints would force
@@ -27,6 +27,8 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h" /* stdio.h must precede rtl.h for FFS.  */
 #include "tm_p.h"
 #include "insn-config.h"
@@ -37,16 +39,19 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "function.h"
 #include "expr.h"
-#include "insn-flags.h"
 #include "basic-block.h"
+#include "except.h"
 #include "toplev.h"
+#include "reload.h"
+#include "timevar.h"
+#include "tree-pass.h"
 
-static int optimize_reg_copy_1 PARAMS ((rtx, rtx, rtx));
-static void optimize_reg_copy_2        PARAMS ((rtx, rtx, rtx));
-static void optimize_reg_copy_3        PARAMS ((rtx, rtx, rtx));
-static rtx gen_add3_insn       PARAMS ((rtx, rtx, rtx));
-static void copy_src_to_dest   PARAMS ((rtx, rtx, rtx, int));
-static int *regmove_bb_head;
+
+static int perhaps_ends_bb_p (rtx);
+static int optimize_reg_copy_1 (rtx, rtx, rtx);
+static void optimize_reg_copy_2 (rtx, rtx, rtx);
+static void optimize_reg_copy_3 (rtx, rtx, rtx);
+static void copy_src_to_dest (rtx, rtx, rtx);
 
 struct match {
   int with[MAX_RECOG_OPERANDS];
@@ -55,25 +60,23 @@ struct match {
   int early_clobber[MAX_RECOG_OPERANDS];
 };
 
-static rtx discover_flags_reg PARAMS ((void));
-static void mark_flags_life_zones PARAMS ((rtx));
-static void flags_set_1 PARAMS ((rtx, rtx, void *));
-
-static int try_auto_increment PARAMS ((rtx, rtx, rtx, rtx, HOST_WIDE_INT, int));
-static int find_matches PARAMS ((rtx, struct match *));
-static int fixup_match_1 PARAMS ((rtx, rtx, rtx, rtx, rtx, int, int, int, FILE *))
-;
-static int reg_is_remote_constant_p PARAMS ((rtx, rtx, rtx));
-static int stable_and_no_regs_but_for_p PARAMS ((rtx, rtx, rtx));
-static int regclass_compatible_p PARAMS ((int, int));
-static int replacement_quality PARAMS ((rtx));
-static int fixup_match_2 PARAMS ((rtx, rtx, rtx, rtx, FILE *));
-
-/* Return non-zero if registers with CLASS1 and CLASS2 can be merged without
+static rtx discover_flags_reg (void);
+static void mark_flags_life_zones (rtx);
+static void flags_set_1 (rtx, rtx, void *);
+
+static int try_auto_increment (rtx, rtx, rtx, rtx, HOST_WIDE_INT, int);
+static int find_matches (rtx, struct match *);
+static void replace_in_call_usage (rtx *, unsigned int, rtx, rtx);
+static int fixup_match_1 (rtx, rtx, rtx, rtx, rtx, int, int, int);
+static int stable_and_no_regs_but_for_p (rtx, rtx, rtx);
+static int regclass_compatible_p (int, int);
+static int replacement_quality (rtx);
+static int fixup_match_2 (rtx, rtx, rtx, rtx);
+
+/* Return nonzero if registers with CLASS1 and CLASS2 can be merged without
    causing too much register allocation problems.  */
 static int
-regclass_compatible_p (class0, class1)
-     int class0, class1;
+regclass_compatible_p (int class0, int class1)
 {
   return (class0 == class1
          || (reg_class_subset_p (class0, class1)
@@ -82,36 +85,13 @@ regclass_compatible_p (class0, class1)
              && ! CLASS_LIKELY_SPILLED_P (class1)));
 }
 
-/* Generate and return an insn body to add r1 and c,
-   storing the result in r0.  */
-static rtx
-gen_add3_insn (r0, r1, c)
-     rtx r0, r1, c;
-{
-  int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code;
-
-    if (icode == CODE_FOR_nothing
-      || ! ((*insn_data[icode].operand[0].predicate)
-           (r0, insn_data[icode].operand[0].mode))
-      || ! ((*insn_data[icode].operand[1].predicate)
-           (r1, insn_data[icode].operand[1].mode))
-      || ! ((*insn_data[icode].operand[2].predicate)
-           (c, insn_data[icode].operand[2].mode)))
-    return NULL_RTX;
-
-  return (GEN_FCN (icode) (r0, r1, c));
-}
-
-
 /* INC_INSN is an instruction that adds INCREMENT to REG.
    Try to fold INC_INSN as a post/pre in/decrement into INSN.
    Iff INC_INSN_SET is nonzero, inc_insn has a destination different from src.
    Return nonzero for success.  */
 static int
-try_auto_increment (insn, inc_insn, inc_insn_set, reg, increment, pre)
-     rtx reg, insn, inc_insn ,inc_insn_set;
-     HOST_WIDE_INT increment;
-     int pre;
+try_auto_increment (rtx insn, rtx inc_insn, rtx inc_insn_set, rtx reg,
+                   HOST_WIDE_INT increment, int pre)
 {
   enum rtx_code inc_code;
 
@@ -121,7 +101,7 @@ try_auto_increment (insn, inc_insn, inc_insn_set, reg, increment, pre)
       /* Can't use the size of SET_SRC, we might have something like
         (sign_extend:SI (mem:QI ...  */
       rtx use = find_use_as_address (pset, reg, 0);
-      if (use != 0 && use != (rtx) 1)
+      if (use != 0 && use != (rtx) (size_t) 1)
        {
          int size = GET_MODE_SIZE (GET_MODE (use));
          if (0
@@ -137,22 +117,28 @@ try_auto_increment (insn, inc_insn, inc_insn_set, reg, increment, pre)
            {
              if (inc_insn_set)
                validate_change
-                 (inc_insn, 
+                 (inc_insn,
                   &SET_SRC (inc_insn_set),
                   XEXP (SET_SRC (inc_insn_set), 0), 1);
              validate_change (insn, &XEXP (use, 0),
                               gen_rtx_fmt_e (inc_code, Pmode, reg), 1);
              if (apply_change_group ())
                {
+                 /* If there is a REG_DEAD note on this insn, we must
+                    change this not to REG_UNUSED meaning that the register
+                    is set, but the value is dead.  Failure to do so will
+                    result in a sched1 dieing -- when it recomputes lifetime
+                    information, the number of REG_DEAD notes will have
+                    changed.  */
+                 rtx note = find_reg_note (insn, REG_DEAD, reg);
+                 if (note)
+                   PUT_MODE (note, REG_UNUSED);
+
                  REG_NOTES (insn)
                    = gen_rtx_EXPR_LIST (REG_INC,
                                         reg, REG_NOTES (insn));
                  if (! inc_insn_set)
-                   {
-                     PUT_CODE (inc_insn, NOTE);
-                     NOTE_LINE_NUMBER (inc_insn) = NOTE_INSN_DELETED;
-                     NOTE_SOURCE_FILE (inc_insn) = 0;
-                   }
+                   delete_insn (inc_insn);
                  return 1;
                }
            }
@@ -169,13 +155,13 @@ try_auto_increment (insn, inc_insn, inc_insn_set, reg, increment, pre)
    if no flags were found.  Return pc_rtx if we got confused.  */
 
 static rtx
-discover_flags_reg ()
+discover_flags_reg (void)
 {
   rtx tmp;
   tmp = gen_rtx_REG (word_mode, 10000);
-  tmp = gen_add3_insn (tmp, tmp, GEN_INT (2));
+  tmp = gen_add3_insn (tmp, tmp, const2_rtx);
 
-  /* If we get something that isn't a simple set, or a 
+  /* If we get something that isn't a simple set, or a
      [(set ..) (clobber ..)], this whole function will go wrong.  */
   if (GET_CODE (tmp) == SET)
     return NULL_RTX;
@@ -194,10 +180,10 @@ discover_flags_reg ()
         scratch or something.  We only care about hard regs.
         Moreover we don't like the notion of subregs of hard regs.  */
       if (GET_CODE (tmp) == SUBREG
-         && GET_CODE (SUBREG_REG (tmp)) == REG
+         && REG_P (SUBREG_REG (tmp))
          && REGNO (SUBREG_REG (tmp)) < FIRST_PSEUDO_REGISTER)
        return pc_rtx;
-      found = (GET_CODE (tmp) == REG && REGNO (tmp) < FIRST_PSEUDO_REGISTER);
+      found = (REG_P (tmp) && REGNO (tmp) < FIRST_PSEUDO_REGISTER);
 
       return (found ? tmp : NULL_RTX);
     }
@@ -208,7 +194,7 @@ discover_flags_reg ()
 /* It is a tedious task identifying when the flags register is live and
    when it is safe to optimize.  Since we process the instruction stream
    multiple times, locate and record these live zones by marking the
-   mode of the instructions -- 
+   mode of the instructions --
 
    QImode is used on the instruction at which the flags becomes live.
 
@@ -222,12 +208,11 @@ static rtx flags_set_1_rtx;
 static int flags_set_1_set;
 
 static void
-mark_flags_life_zones (flags)
-     rtx flags;
+mark_flags_life_zones (rtx flags)
 {
   int flags_regno;
   int flags_nregs;
-  int block;
+  basic_block block;
 
 #ifdef HAVE_cc0
   /* If we found a flags register on a cc0 host, bail.  */
@@ -236,14 +221,14 @@ mark_flags_life_zones (flags)
   else if (flags != cc0_rtx)
     flags = pc_rtx;
 #endif
-    
+
   /* Simple cases first: if no flags, clear all modes.  If confusing,
      mark the entire function as being in a flags shadow.  */
   if (flags == NULL_RTX || flags == pc_rtx)
     {
       enum machine_mode mode = (flags ? HImode : VOIDmode);
       rtx insn;
-      for (insn = get_insns(); insn; insn = NEXT_INSN (insn))
+      for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
        PUT_MODE (insn, mode);
       return;
     }
@@ -253,18 +238,18 @@ mark_flags_life_zones (flags)
   flags_nregs = 1;
 #else
   flags_regno = REGNO (flags);
-  flags_nregs = HARD_REGNO_NREGS (flags_regno, GET_MODE (flags));
+  flags_nregs = hard_regno_nregs[flags_regno][GET_MODE (flags)];
 #endif
   flags_set_1_rtx = flags;
 
   /* Process each basic block.  */
-  for (block = n_basic_blocks - 1; block >= 0; block--)
+  FOR_EACH_BB_REVERSE (block)
     {
       rtx insn, end;
       int live;
 
-      insn = BLOCK_HEAD (block);
-      end = BLOCK_END (block);
+      insn = BB_HEAD (block);
+      end = BB_END (block);
 
       /* Look out for the (unlikely) case of flags being live across
         basic block boundaries.  */
@@ -273,7 +258,7 @@ mark_flags_life_zones (flags)
       {
        int i;
        for (i = 0; i < flags_nregs; ++i)
-          live |= REGNO_REG_SET_P (BASIC_BLOCK (block)->global_live_at_start,
+         live |= REGNO_REG_SET_P (block->il.rtl->global_live_at_start,
                                   flags_regno + i);
       }
 #endif
@@ -298,7 +283,7 @@ mark_flags_life_zones (flags)
 #endif
              PUT_MODE (insn, (live ? HImode : VOIDmode));
 
-             /* In either case, birth is denoted simply by it's presence
+             /* In either case, birth is denoted simply by its presence
                 as the destination of a set.  */
              flags_set_1_set = 0;
              note_stores (PATTERN (insn), flags_set_1, NULL);
@@ -321,9 +306,7 @@ mark_flags_life_zones (flags)
 /* A subroutine of mark_flags_life_zones, called through note_stores.  */
 
 static void
-flags_set_1 (x, pat, data)
-     rtx x, pat;
-     void *data ATTRIBUTE_UNUSED;
+flags_set_1 (rtx x, rtx pat, void *data ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (pat) == SET
       && reg_overlap_mentioned_p (x, flags_set_1_rtx))
@@ -338,13 +321,12 @@ static int *regno_src_regno;
    a candidate for tying to a hard register, since the output might in
    turn be a candidate to be tied to a different hard register.  */
 static int
-replacement_quality(reg)
-     rtx reg;
+replacement_quality (rtx reg)
 {
   int src_regno;
 
   /* Bad if this isn't a register at all.  */
-  if (GET_CODE (reg) != REG)
+  if (!REG_P (reg))
     return 0;
 
   /* If this register is not meant to get a hard register,
@@ -367,23 +349,43 @@ replacement_quality(reg)
      when the registers get tied.  */
   return 2;
 }
+\f
+/* Return 1 if INSN might end a basic block.  */
 
+static int perhaps_ends_bb_p (rtx insn)
+{
+  switch (GET_CODE (insn))
+    {
+    case CODE_LABEL:
+    case JUMP_INSN:
+      /* These always end a basic block.  */
+      return 1;
+
+    case CALL_INSN:
+      /* A CALL_INSN might be the last insn of a basic block, if it is inside
+        an EH region or if there are nonlocal gotos.  Note that this test is
+        very conservative.  */
+      if (nonlocal_goto_handler_labels)
+       return 1;
+      /* Fall through.  */
+    default:
+      return can_throw_internal (insn);
+    }
+}
+\f
 /* INSN is a copy from SRC to DEST, both registers, and SRC does not die
    in INSN.
 
    Search forward to see if SRC dies before either it or DEST is modified,
    but don't scan past the end of a basic block.  If so, we can replace SRC
-   with DEST and let SRC die in INSN. 
+   with DEST and let SRC die in INSN.
 
    This will reduce the number of registers live in that range and may enable
    DEST to be tied to SRC, thus often saving one register in addition to a
    register-register copy.  */
 
 static int
-optimize_reg_copy_1 (insn, dest, src)
-     rtx insn;
-     rtx dest;
-     rtx src;
+optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
 {
   rtx p, q;
   rtx note;
@@ -391,7 +393,7 @@ optimize_reg_copy_1 (insn, dest, src)
   int sregno = REGNO (src);
   int dregno = REGNO (dest);
 
-  /* We don't want to mess with hard regs if register classes are small. */
+  /* We don't want to mess with hard regs if register classes are small.  */
   if (sregno == dregno
       || (SMALL_REGISTER_CLASSES
          && (sregno < FIRST_PSEUDO_REGISTER
@@ -403,21 +405,27 @@ optimize_reg_copy_1 (insn, dest, src)
 
   for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
     {
-      if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
-       break;
-
       /* ??? We can't scan past the end of a basic block without updating
-        the register lifetime info (REG_DEAD/basic_block_live_at_start).
-        A CALL_INSN might be the last insn of a basic block, if it is inside
-        an EH region.  There is no easy way to tell, so we just always break
-        when we see a CALL_INSN if flag_exceptions is nonzero.  */
-      if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+        the register lifetime info (REG_DEAD/basic_block_live_at_start).  */
+      if (perhaps_ends_bb_p (p))
        break;
-
-      if (! INSN_P (p))
+      else if (! INSN_P (p))
        continue;
 
       if (reg_set_p (src, p) || reg_set_p (dest, p)
+         /* If SRC is an asm-declared register, it must not be replaced
+            in any asm.  Unfortunately, the REG_EXPR tree for the asm
+            variable may be absent in the SRC rtx, so we can't check the
+            actual register declaration easily (the asm operand will have
+            it, though).  To avoid complicating the test for a rare case,
+            we just don't perform register replacement for a hard reg
+            mentioned in an asm.  */
+         || (sregno < FIRST_PSEUDO_REGISTER
+             && asm_noperands (PATTERN (p)) >= 0
+             && reg_overlap_mentioned_p (src, PATTERN (p)))
+         /* Don't change hard registers used by a call.  */
+         || (CALL_P (p) && sregno < FIRST_PSEUDO_REGISTER
+             && find_reg_fusage (p, USE, src))
          /* Don't change a USE of a register.  */
          || (GET_CODE (PATTERN (p)) == USE
              && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
@@ -454,15 +462,15 @@ optimize_reg_copy_1 (insn, dest, src)
                  if (sregno < FIRST_PSEUDO_REGISTER
                      && reg_mentioned_p (dest, PATTERN (q)))
                    failed = 1;
+                 
+                 /* Attempt to replace all uses.  */
+                 else if (!validate_replace_rtx (src, dest, q))
+                   failed = 1;
 
-                 /* Replace all uses and make sure that the register
-                    isn't still present.  */
-                 else if (validate_replace_rtx (src, dest, q)
-                          && (sregno >= FIRST_PSEUDO_REGISTER
-                              || ! reg_overlap_mentioned_p (src,
-                                                            PATTERN (q))))
-                   ;
-                 else
+                 /* If this succeeded, but some part of the register
+                    is still present, undo the replacement.  */
+                 else if (sregno < FIRST_PSEUDO_REGISTER
+                          && reg_overlap_mentioned_p (src, PATTERN (q)))
                    {
                      validate_replace_rtx (dest, src, q);
                      failed = 1;
@@ -478,7 +486,7 @@ optimize_reg_copy_1 (insn, dest, src)
 
              /* If the insn in which SRC dies is a CALL_INSN, don't count it
                 as a call that has been crossed.  Otherwise, count it.  */
-             if (q != p && GET_CODE (q) == CALL_INSN)
+             if (q != p && CALL_P (q))
                {
                  /* Similarly, total calls for SREGNO, total calls beyond
                     the death note for DREGNO.  */
@@ -576,10 +584,7 @@ optimize_reg_copy_1 (insn, dest, src)
    this for hard registers since the substitutions we may make might fail.  */
 
 static void
-optimize_reg_copy_2 (insn, dest, src)
-     rtx insn;
-     rtx dest;
-     rtx src;
+optimize_reg_copy_2 (rtx insn, rtx dest, rtx src)
 {
   rtx p, q;
   rtx set;
@@ -588,18 +593,11 @@ optimize_reg_copy_2 (insn, dest, src)
 
   for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
     {
-      if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
-       break;
-
       /* ??? We can't scan past the end of a basic block without updating
-        the register lifetime info (REG_DEAD/basic_block_live_at_start).
-        A CALL_INSN might be the last insn of a basic block, if it is inside
-        an EH region.  There is no easy way to tell, so we just always break
-        when we see a CALL_INSN if flag_exceptions is nonzero.  */
-      if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+        the register lifetime info (REG_DEAD/basic_block_live_at_start).  */
+      if (perhaps_ends_bb_p (p))
        break;
-
-      if (! INSN_P (p))
+      else if (! INSN_P (p))
        continue;
 
       set = single_set (p);
@@ -616,12 +614,11 @@ optimize_reg_copy_2 (insn, dest, src)
                if (reg_mentioned_p (dest, PATTERN (q)))
                  PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
 
-
-             if (GET_CODE (q) == CALL_INSN)
-               {
-                 REG_N_CALLS_CROSSED (dregno)--;
-                 REG_N_CALLS_CROSSED (sregno)++;
-               }
+               if (CALL_P (q))
+                 {
+                   REG_N_CALLS_CROSSED (dregno)--;
+                   REG_N_CALLS_CROSSED (sregno)++;
+                 }
              }
 
          remove_note (p, find_reg_note (p, REG_DEAD, dest));
@@ -633,58 +630,50 @@ optimize_reg_copy_2 (insn, dest, src)
 
       if (reg_set_p (src, p)
          || find_reg_note (p, REG_DEAD, dest)
-         || (GET_CODE (p) == CALL_INSN && REG_N_CALLS_CROSSED (sregno) == 0))
+         || (CALL_P (p) && REG_N_CALLS_CROSSED (sregno) == 0))
        break;
     }
 }
+
 /* INSN is a ZERO_EXTEND or SIGN_EXTEND of SRC to DEST.
    Look if SRC dies there, and if it is only set once, by loading
-   it from memory.  If so, try to encorporate the zero/sign extension
+   it from memory.  If so, try to incorporate the zero/sign extension
    into the memory read, change SRC to the mode of DEST, and alter
    the remaining accesses to use the appropriate SUBREG.  This allows
    SRC and DEST to be tied later.  */
 static void
-optimize_reg_copy_3 (insn, dest, src)
-     rtx insn;
-     rtx dest;
-     rtx src;
+optimize_reg_copy_3 (rtx insn, rtx dest, rtx src)
 {
   rtx src_reg = XEXP (src, 0);
   int src_no = REGNO (src_reg);
   int dst_no = REGNO (dest);
-  rtx p, set, subreg;
+  rtx p, set;
   enum machine_mode old_mode;
 
   if (src_no < FIRST_PSEUDO_REGISTER
       || dst_no < FIRST_PSEUDO_REGISTER
       || ! find_reg_note (insn, REG_DEAD, src_reg)
+      || REG_N_DEATHS (src_no) != 1
       || REG_N_SETS (src_no) != 1)
     return;
   for (p = PREV_INSN (insn); p && ! reg_set_p (src_reg, p); p = PREV_INSN (p))
-    {
-      if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
-       return;
-
-      /* ??? We can't scan past the end of a basic block without updating
-        the register lifetime info (REG_DEAD/basic_block_live_at_start).
-        A CALL_INSN might be the last insn of a basic block, if it is inside
-        an EH region.  There is no easy way to tell, so we just always break
-        when we see a CALL_INSN if flag_exceptions is nonzero.  */
-      if (flag_exceptions && GET_CODE (p) == CALL_INSN)
-       return;
+    /* ??? We can't scan past the end of a basic block without updating
+       the register lifetime info (REG_DEAD/basic_block_live_at_start).  */
+    if (perhaps_ends_bb_p (p))
+      break;
 
-      if (! INSN_P (p))
-       continue;
-    }
   if (! p)
     return;
 
   if (! (set = single_set (p))
-      || GET_CODE (SET_SRC (set)) != MEM
+      || !MEM_P (SET_SRC (set))
+      /* If there's a REG_EQUIV note, this must be an insn that loads an
+        argument.  Prefer keeping the note over doing this optimization.  */
+      || find_reg_note (p, REG_EQUIV, NULL_RTX)
       || SET_DEST (set) != src_reg)
     return;
 
-  /* Be conserative: although this optimization is also valid for
+  /* Be conservative: although this optimization is also valid for
      volatile memory references, that could cause trouble in later passes.  */
   if (MEM_VOLATILE_P (SET_SRC (set)))
     return;
@@ -706,14 +695,15 @@ optimize_reg_copy_3 (insn, dest, src)
 
   /* Now walk forward making additional replacements.  We want to be able
      to undo all the changes if a later substitution fails.  */
-  subreg = gen_rtx_SUBREG (old_mode, src_reg, 0);
   while (p = NEXT_INSN (p), p != insn)
     {
       if (! INSN_P (p))
        continue;
 
-      /* Make a tenative change.  */
-      validate_replace_rtx_group (src_reg, subreg, p);
+      /* Make a tentative change.  */
+      validate_replace_rtx_group (src_reg,
+                                 gen_lowpart_SUBREG (old_mode, src_reg),
+                                 p);
     }
 
   validate_replace_rtx_group (src, src_reg, insn);
@@ -725,6 +715,12 @@ optimize_reg_copy_3 (insn, dest, src)
       PUT_MODE (src_reg, old_mode);
       XEXP (src, 0) = src_reg;
     }
+  else
+    {
+      rtx note = find_reg_note (p, REG_EQUAL, NULL_RTX);
+      if (note)
+       remove_note (p, note);
+    }
 }
 
 \f
@@ -732,11 +728,7 @@ optimize_reg_copy_3 (insn, dest, src)
    instead moving the value to dest directly before the operation.  */
 
 static void
-copy_src_to_dest (insn, src, dest, old_max_uid)
-     rtx insn;
-     rtx src;
-     rtx dest;
-     int old_max_uid;
+copy_src_to_dest (rtx insn, rtx src, rtx dest)
 {
   rtx seq;
   rtx link;
@@ -756,10 +748,9 @@ copy_src_to_dest (insn, src, dest, old_max_uid)
      parameter when there is no frame pointer that is not allocated a register.
      For now, we just reject them, rather than incrementing the live length.  */
 
-  if (GET_CODE (src) == REG
+  if (REG_P (src)
       && REG_LIVE_LENGTH (REGNO (src)) > 0
-      && GET_CODE (dest) == REG
-      && !RTX_UNCHANGING_P (dest)
+      && REG_P (dest)
       && REG_LIVE_LENGTH (REGNO (dest)) > 0
       && (set = single_set (insn)) != NULL_RTX
       && !reg_mentioned_p (dest, SET_SRC (set))
@@ -770,7 +761,7 @@ copy_src_to_dest (insn, src, dest, old_max_uid)
       /* Generate the src->dest move.  */
       start_sequence ();
       emit_move_insn (dest, src);
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
       /* If this sequence uses new registers, we may not use it.  */
       if (old_num_regs != reg_rtx_no
@@ -787,7 +778,7 @@ copy_src_to_dest (insn, src, dest, old_max_uid)
       p_move_notes = &REG_NOTES (move_insn);
       p_insn_notes = &REG_NOTES (insn);
 
-      /* Move any notes mentioning src to the move instruction */
+      /* Move any notes mentioning src to the move instruction */
       for (link = REG_NOTES (insn); link != NULL_RTX; link = next)
        {
          next = XEXP (link, 1);
@@ -806,18 +797,8 @@ copy_src_to_dest (insn, src, dest, old_max_uid)
       *p_move_notes = NULL_RTX;
       *p_insn_notes = NULL_RTX;
 
-      /* Is the insn the head of a basic block?  If so extend it */
       insn_uid = INSN_UID (insn);
       move_uid = INSN_UID (move_insn);
-      if (insn_uid < old_max_uid)
-       {
-         bb = regmove_bb_head[insn_uid];
-         if (bb >= 0)
-           {
-             BLOCK_HEAD (bb) = move_insn;
-             regmove_bb_head[insn_uid] = -1;
-           }
-       }
 
       /* Update the various register tables.  */
       dest_regno = REGNO (dest);
@@ -835,12 +816,17 @@ copy_src_to_dest (insn, src, dest, old_max_uid)
 
       if (REGNO_LAST_UID (src_regno) == insn_uid)
        REGNO_LAST_UID (src_regno) = move_uid;
-
-      if (REGNO_LAST_NOTE_UID (src_regno) == insn_uid)
-       REGNO_LAST_NOTE_UID (src_regno) = move_uid;
     }
 }
 
+/* reg_set_in_bb[REGNO] points to basic block iff the register is set
+   only once in the given block and has REG_EQUAL note.  */
+
+basic_block *reg_set_in_bb;
+
+/* Size of reg_set_in_bb array.  */
+static unsigned int max_reg_computed;
+
 \f
 /* Return whether REG is set in only one location, and is set to a
    constant, but is set in a different basic block from INSN (an
@@ -849,57 +835,42 @@ copy_src_to_dest (insn, src, dest, old_max_uid)
    may increase register pressure and make reload harder.  If REG is
    set in the same basic block as INSN, we don't worry about it,
    because we'll probably need a register anyhow (??? but what if REG
-   is used in a different basic block as well as this one?).  FIRST is
-   the first insn in the function.  */
+   is used in a different basic block as well as this one?).  */
 
-static int
-reg_is_remote_constant_p (reg, insn, first)
-     rtx reg;
-     rtx insn;
-     rtx first;
+static bool
+reg_is_remote_constant_p (rtx reg, rtx insn)
 {
-  register rtx p;
-
-  if (REG_N_SETS (REGNO (reg)) != 1)
-    return 0;
-
-  /* Look for the set.  */
-  for (p = LOG_LINKS (insn); p; p = XEXP (p, 1))
-    {
-      rtx s;
-
-      if (REG_NOTE_KIND (p) != 0)
-       continue;
-      s = single_set (XEXP (p, 0));
-      if (s != 0
-         && GET_CODE (SET_DEST (s)) == REG
-         && REGNO (SET_DEST (s)) == REGNO (reg))
-       {
-         /* The register is set in the same basic block.  */
-         return 0;
-       }
-    }
+  basic_block bb;
+  rtx p;
+  int max;
 
-  for (p = first; p && p != insn; p = NEXT_INSN (p))
+  if (!reg_set_in_bb)
     {
-      rtx s;
+      max_reg_computed = max = max_reg_num ();
+      reg_set_in_bb = xcalloc (max, sizeof (*reg_set_in_bb));
 
-      if (! INSN_P (p))
-       continue;
-      s = single_set (p);
-      if (s != 0
-         && GET_CODE (SET_DEST (s)) == REG
-         && REGNO (SET_DEST (s)) == REGNO (reg))
-       {
-         /* This is the instruction which sets REG.  If there is a
-             REG_EQUAL note, then REG is equivalent to a constant.  */
-         if (find_reg_note (p, REG_EQUAL, NULL_RTX))
-           return 1;
-         return 0;
-       }
+      FOR_EACH_BB (bb)
+       FOR_BB_INSNS (bb, p)
+         {
+           rtx s;
+
+           if (!INSN_P (p))
+             continue;
+           s = single_set (p);
+           /* This is the instruction which sets REG.  If there is a
+              REG_EQUAL note, then REG is equivalent to a constant.  */
+           if (s != 0
+               && REG_P (SET_DEST (s))
+               && REG_N_SETS (REGNO (SET_DEST (s))) == 1
+               && find_reg_note (p, REG_EQUAL, NULL_RTX))
+             reg_set_in_bb[REGNO (SET_DEST (s))] = bb;
+         }
     }
 
-  return 0;
+  gcc_assert (REGNO (reg) < max_reg_computed);
+  if (reg_set_in_bb[REGNO (reg)] == NULL)
+    return false;
+  return (reg_set_in_bb[REGNO (reg)] != BLOCK_FOR_INSN (insn));
 }
 
 /* INSN is adding a CONST_INT to a REG.  We search backwards looking for
@@ -917,13 +888,11 @@ reg_is_remote_constant_p (reg, insn, first)
      (set (reg100) (plus reg100 offset2-offset1))  */
 
 /* ??? What does this comment mean?  */
-/* cse disrupts preincrement / postdecrement squences when it finds a
+/* cse disrupts preincrement / postdecrement sequences when it finds a
    hard register as ultimate source, like the frame pointer.  */
 
 static int
-fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
-     rtx insn, dst, src, offset;
-     FILE *regmove_dump_file;
+fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset)
 {
   rtx p, dst_death = 0;
   int length, num_calls = 0;
@@ -940,20 +909,12 @@ fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
     {
       rtx pset;
 
-      if (GET_CODE (p) == CODE_LABEL
-          || GET_CODE (p) == JUMP_INSN)
-        break;
-
       /* ??? We can't scan past the end of a basic block without updating
-        the register lifetime info (REG_DEAD/basic_block_live_at_start).
-        A CALL_INSN might be the last insn of a basic block, if it is inside
-        an EH region.  There is no easy way to tell, so we just always break
-        when we see a CALL_INSN if flag_exceptions is nonzero.  */
-      if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+        the register lifetime info (REG_DEAD/basic_block_live_at_start).  */
+      if (perhaps_ends_bb_p (p))
        break;
-
-      if (! INSN_P (p))
-        continue;
+      else if (! INSN_P (p))
+       continue;
 
       if (find_regno_note (p, REG_DEAD, REGNO (dst)))
        dst_death = p;
@@ -965,7 +926,7 @@ fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
          && GET_CODE (SET_SRC (pset)) == PLUS
          && XEXP (SET_SRC (pset), 0) == src
          && GET_CODE (XEXP (SET_SRC (pset), 1)) == CONST_INT)
-        {
+       {
          HOST_WIDE_INT newconst
            = INTVAL (offset) - INTVAL (XEXP (SET_SRC (pset), 1));
          rtx add = gen_add3_insn (dst, dst, GEN_INT (newconst));
@@ -980,16 +941,16 @@ fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
                  REG_N_CALLS_CROSSED (REGNO (dst)) += num_calls;
                }
 
-             if (regmove_dump_file)
-               fprintf (regmove_dump_file,
+             if (dump_file)
+               fprintf (dump_file,
                         "Fixed operand of insn %d.\n",
                          INSN_UID (insn));
 
 #ifdef AUTO_INC_DEC
              for (p = PREV_INSN (insn); p; p = PREV_INSN (p))
                {
-                 if (GET_CODE (p) == CODE_LABEL
-                     || GET_CODE (p) == JUMP_INSN)
+                 if (LABEL_P (p)
+                     || JUMP_P (p))
                    break;
                  if (! INSN_P (p))
                    continue;
@@ -1002,8 +963,8 @@ fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
                }
              for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
                {
-                 if (GET_CODE (p) == CODE_LABEL
-                     || GET_CODE (p) == JUMP_INSN)
+                 if (LABEL_P (p)
+                     || JUMP_P (p))
                    break;
                  if (! INSN_P (p))
                    continue;
@@ -1016,10 +977,10 @@ fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
 #endif
              return 1;
            }
-        }
+       }
 
       if (reg_set_p (dst, PATTERN (p)))
-        break;
+       break;
 
       /* If we have passed a call instruction, and the
          pseudo-reg SRC is not already live across a call,
@@ -1027,49 +988,53 @@ fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
       /* reg_set_p is overly conservative for CALL_INSNS, thinks that all
         hard regs are clobbered.  Thus, we only use it for src for
         non-call insns.  */
-      if (GET_CODE (p) == CALL_INSN)
-        {
+      if (CALL_P (p))
+       {
          if (! dst_death)
            num_calls++;
 
-          if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
-            break;
+         if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
+           break;
 
          if (call_used_regs [REGNO (dst)]
              || find_reg_fusage (p, CLOBBER, dst))
            break;
-        }
+       }
       else if (reg_set_p (src, PATTERN (p)))
-        break;
+       break;
     }
 
   return 0;
 }
 
-void
-regmove_optimize (f, nregs, regmove_dump_file)
-     rtx f;
-     int nregs;
-     FILE *regmove_dump_file;
+/* Main entry for the register move optimization.
+   F is the first instruction.
+   NREGS is one plus the highest pseudo-reg number used in the instruction.
+   REGMOVE_DUMP_FILE is a stream for output of a trace of actions taken
+   (or 0 if none should be output).  */
+
+static void
+regmove_optimize (rtx f, int nregs)
 {
-  int old_max_uid = get_max_uid ();
   rtx insn;
   struct match match;
   int pass;
   int i;
   rtx copy_src, copy_dst;
+  basic_block bb;
+
+  /* ??? Hack.  Regmove doesn't examine the CFG, and gets mightily
+     confused by non-call exceptions ending blocks.  */
+  if (flag_non_call_exceptions)
+    return;
 
   /* Find out where a potential flags register is live, and so that we
-     can supress some optimizations in those zones.  */
+     can suppress some optimizations in those zones.  */
   mark_flags_life_zones (discover_flags_reg ());
 
-  regno_src_regno = (int *) xmalloc (sizeof *regno_src_regno * nregs);
-  for (i = nregs; --i >= 0; ) regno_src_regno[i] = -1;
-
-  regmove_bb_head = (int *) xmalloc (sizeof (int) * (old_max_uid + 1));
-  for (i = old_max_uid; i >= 0; i--) regmove_bb_head[i] = -1;
-  for (i = 0; i < n_basic_blocks; i++)
-    regmove_bb_head[INSN_UID (BLOCK_HEAD (i))] = i;
+  regno_src_regno = XNEWVEC (int, nregs);
+  for (i = nregs; --i >= 0; )
+    regno_src_regno[i] = -1;
 
   /* A forward/backward pass.  Replace output operands with input operands.  */
 
@@ -1078,8 +1043,8 @@ regmove_optimize (f, nregs, regmove_dump_file)
       if (! flag_regmove && pass >= flag_expensive_optimizations)
        goto done;
 
-      if (regmove_dump_file)
-       fprintf (regmove_dump_file, "Starting %s pass...\n",
+      if (dump_file)
+       fprintf (dump_file, "Starting %s pass...\n",
                 pass ? "backward" : "forward");
 
       for (insn = pass ? get_last_insn () : f; insn;
@@ -1095,13 +1060,13 @@ regmove_optimize (f, nregs, regmove_dump_file)
          if (flag_expensive_optimizations && ! pass
              && (GET_CODE (SET_SRC (set)) == SIGN_EXTEND
                  || GET_CODE (SET_SRC (set)) == ZERO_EXTEND)
-             && GET_CODE (XEXP (SET_SRC (set), 0)) == REG
-             && GET_CODE (SET_DEST(set)) == REG)
+             && REG_P (XEXP (SET_SRC (set), 0))
+             && REG_P (SET_DEST (set)))
            optimize_reg_copy_3 (insn, SET_DEST (set), SET_SRC (set));
 
          if (flag_expensive_optimizations && ! pass
-             && GET_CODE (SET_SRC (set)) == REG
-             && GET_CODE (SET_DEST(set)) == REG)
+             && REG_P (SET_SRC (set))
+             && REG_P (SET_DEST (set)))
            {
              /* If this is a register-register copy where SRC is not dead,
                 see if we can optimize it.  If this optimization succeeds,
@@ -1116,15 +1081,15 @@ regmove_optimize (f, nregs, regmove_dump_file)
                  if (regno_src_regno[REGNO (SET_DEST (set))] < 0
                      && SET_SRC (set) != SET_DEST (set))
                    {
-                     int srcregno = REGNO (SET_SRC(set));
+                     int srcregno = REGNO (SET_SRC (set));
                      if (regno_src_regno[srcregno] >= 0)
                        srcregno = regno_src_regno[srcregno];
                      regno_src_regno[REGNO (SET_DEST (set))] = srcregno;
                    }
                }
            }
-          if (! flag_regmove)
-            continue;
+         if (! flag_regmove)
+           continue;
 
          if (! find_matches (insn, &match))
            continue;
@@ -1150,7 +1115,7 @@ regmove_optimize (f, nregs, regmove_dump_file)
              src = recog_data.operand[op_no];
              dst = recog_data.operand[match_no];
 
-             if (GET_CODE (src) != REG)
+             if (!REG_P (src))
                continue;
 
              src_subreg = src;
@@ -1158,12 +1123,13 @@ regmove_optimize (f, nregs, regmove_dump_file)
                  && GET_MODE_SIZE (GET_MODE (dst))
                     >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dst))))
                {
-                 src_subreg
-                   = gen_rtx_SUBREG (GET_MODE (SUBREG_REG (dst)),
-                                     src, SUBREG_WORD (dst));
                  dst = SUBREG_REG (dst);
+                 src_subreg = lowpart_subreg (GET_MODE (dst),
+                                              src, GET_MODE (src));
+                 if (!src_subreg)
+                   continue;
                }
-             if (GET_CODE (dst) != REG
+             if (!REG_P (dst)
                  || REGNO (dst) < FIRST_PSEUDO_REGISTER)
                continue;
 
@@ -1191,7 +1157,7 @@ regmove_optimize (f, nregs, regmove_dump_file)
              if (recog_data.operand[match_no] != SET_DEST (set))
                continue;
 
-             /* If the operands already match, then there is nothing to do. */
+             /* If the operands already match, then there is nothing to do.  */
              if (operands_match_p (src, dst))
                continue;
 
@@ -1209,10 +1175,12 @@ regmove_optimize (f, nregs, regmove_dump_file)
              dst_class = reg_preferred_class (REGNO (dst));
              if (! regclass_compatible_p (src_class, dst_class))
                continue;
-         
+
+             if (GET_MODE (src) != GET_MODE (dst))
+               continue;
+
              if (fixup_match_1 (insn, set, src, src_subreg, dst, pass,
-                                op_no, match_no,
-                                regmove_dump_file))
+                                op_no, match_no))
                break;
            }
        }
@@ -1220,8 +1188,8 @@ regmove_optimize (f, nregs, regmove_dump_file)
 
   /* A backward pass.  Replace input operands with output operands.  */
 
-  if (regmove_dump_file)
-    fprintf (regmove_dump_file, "Starting backward pass...\n");
+  if (dump_file)
+    fprintf (dump_file, "Starting backward pass...\n");
 
   for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
     {
@@ -1258,15 +1226,16 @@ regmove_optimize (f, nregs, regmove_dump_file)
              dst = recog_data.operand[match_no];
              src = recog_data.operand[op_no];
 
-             if (GET_CODE (src) != REG)
+             if (!REG_P (src))
                continue;
 
-             if (GET_CODE (dst) != REG
+             if (!REG_P (dst)
                  || REGNO (dst) < FIRST_PSEUDO_REGISTER
-                 || REG_LIVE_LENGTH (REGNO (dst)) < 0)
+                 || REG_LIVE_LENGTH (REGNO (dst)) < 0
+                 || GET_MODE (src) != GET_MODE (dst))
                continue;
 
-             /* If the operands already match, then there is nothing to do. */
+             /* If the operands already match, then there is nothing to do.  */
              if (operands_match_p (src, dst))
                continue;
 
@@ -1281,6 +1250,14 @@ regmove_optimize (f, nregs, regmove_dump_file)
              if (! set)
                continue;
 
+             /* Note that single_set ignores parts of a parallel set for
+                which one of the destinations is REG_UNUSED.  We can't
+                handle that here, since we can wind up rewriting things
+                such that a single register is set twice within a single
+                parallel.  */
+             if (reg_set_p (src, insn))
+               continue;
+
              /* match_no/dst must be a write-only operand, and
                 operand_operand/src must be a read-only operand.  */
              if (match.use[op_no] != READ
@@ -1301,26 +1278,28 @@ regmove_optimize (f, nregs, regmove_dump_file)
                      && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT
                      && XEXP (SET_SRC (set), 0) == src
                      && fixup_match_2 (insn, dst, src,
-                                       XEXP (SET_SRC (set), 1),
-                                       regmove_dump_file))
+                                       XEXP (SET_SRC (set), 1)))
                    break;
                  continue;
                }
              src_class = reg_preferred_class (REGNO (src));
              dst_class = reg_preferred_class (REGNO (dst));
-             if (! regclass_compatible_p (src_class, dst_class))
+
+             if (! (src_note = find_reg_note (insn, REG_DEAD, src)))
                {
-                 if (!copy_src)
-                   {
-                     copy_src = src;
-                     copy_dst = dst;
-                   }
+                 /* We used to force the copy here like in other cases, but
+                    it produces worse code, as it eliminates no copy
+                    instructions and the copy emitted will be produced by
+                    reload anyway.  On patterns with multiple alternatives,
+                    there may be better solution available.
+
+                    In particular this change produced slower code for numeric
+                    i387 programs.  */
+
                  continue;
                }
 
-             /* Can not modify an earlier insn to set dst if this insn
-                uses an old value in the source.  */
-             if (reg_overlap_mentioned_p (dst, SET_SRC (set)))
+             if (! regclass_compatible_p (src_class, dst_class))
                {
                  if (!copy_src)
                    {
@@ -1330,7 +1309,9 @@ regmove_optimize (f, nregs, regmove_dump_file)
                  continue;
                }
 
-             if (! (src_note = find_reg_note (insn, REG_DEAD, src)))
+             /* Can not modify an earlier insn to set dst if this insn
+                uses an old value in the source.  */
+             if (reg_overlap_mentioned_p (dst, SET_SRC (set)))
                {
                  if (!copy_src)
                    {
@@ -1340,13 +1321,12 @@ regmove_optimize (f, nregs, regmove_dump_file)
                  continue;
                }
 
-
              /* If src is set once in a different basic block,
                 and is set equal to a constant, then do not use
                 it for this optimization, as this would make it
                 no longer equivalent to a constant.  */
 
-              if (reg_is_remote_constant_p (src, insn, f))
+             if (reg_is_remote_constant_p (src, insn))
                {
                  if (!copy_src)
                    {
@@ -1357,8 +1337,8 @@ regmove_optimize (f, nregs, regmove_dump_file)
                }
 
 
-             if (regmove_dump_file)
-               fprintf (regmove_dump_file,
+             if (dump_file)
+               fprintf (dump_file,
                         "Could fix operand %d of insn %d matching operand %d.\n",
                         op_no, INSN_UID (insn), match_no);
 
@@ -1370,21 +1350,12 @@ regmove_optimize (f, nregs, regmove_dump_file)
                {
                  rtx pset;
 
-                 if (GET_CODE (p) == CODE_LABEL
-                     || GET_CODE (p) == JUMP_INSN)
-                   break;
-
                  /* ??? We can't scan past the end of a basic block without
                     updating the register lifetime info
-                    (REG_DEAD/basic_block_live_at_start).
-                    A CALL_INSN might be the last insn of a basic block, if
-                    it is inside an EH region.  There is no easy way to tell,
-                    so we just always break when we see a CALL_INSN if
-                    flag_exceptions is nonzero.  */
-                 if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+                    (REG_DEAD/basic_block_live_at_start).  */
+                 if (perhaps_ends_bb_p (p))
                    break;
-
-                 if (! INSN_P (p))
+                 else if (! INSN_P (p))
                    continue;
 
                  length++;
@@ -1416,14 +1387,19 @@ regmove_optimize (f, nregs, regmove_dump_file)
                      break;
                    }
 
+                 /* We can't make this change if SRC is read or
+                    partially written in P, since we are going to
+                    eliminate SRC. We can't make this change 
+                    if DST is mentioned at all in P,
+                    since we are going to change its value.  */
                  if (reg_overlap_mentioned_p (src, PATTERN (p))
-                     || reg_overlap_mentioned_p (dst, PATTERN (p)))
+                     || reg_mentioned_p (dst, PATTERN (p)))
                    break;
 
                  /* If we have passed a call instruction, and the
                     pseudo-reg DST is not already live across a call,
                     then don't perform the optimization.  */
-                 if (GET_CODE (p) == CALL_INSN)
+                 if (CALL_P (p))
                    {
                      num_calls++;
 
@@ -1470,8 +1446,8 @@ regmove_optimize (f, nregs, regmove_dump_file)
                        REG_LIVE_LENGTH (srcno) = 2;
                    }
 
-                 if (regmove_dump_file)
-                   fprintf (regmove_dump_file,
+                 if (dump_file)
+                   fprintf (dump_file,
                             "Fixed operand %d of insn %d matching operand %d.\n",
                             op_no, INSN_UID (insn), match_no);
 
@@ -1480,30 +1456,21 @@ regmove_optimize (f, nregs, regmove_dump_file)
            }
 
          /* If we weren't able to replace any of the alternatives, try an
-            alternative appoach of copying the source to the destination.  */
+            alternative approach of copying the source to the destination.  */
          if (!success && copy_src != NULL_RTX)
-           copy_src_to_dest (insn, copy_src, copy_dst, old_max_uid);
+           copy_src_to_dest (insn, copy_src, copy_dst);
 
        }
     }
 
-  /* In fixup_match_1, some insns may have been inserted after basic block
-     ends.  Fix that here.  */
-  for (i = 0; i < n_basic_blocks; i++)
-    {
-      rtx end = BLOCK_END (i);
-      rtx new = end;
-      rtx next = NEXT_INSN (new);
-      while (next != 0 && INSN_UID (next) >= old_max_uid
-            && (i == n_basic_blocks - 1 || BLOCK_HEAD (i + 1) != next))
-       new = next, next = NEXT_INSN (new);
-      BLOCK_END (i) = new;
-    }
-
  done:
   /* Clean up.  */
   free (regno_src_regno);
-  free (regmove_bb_head);
+  if (reg_set_in_bb)
+    {
+      free (reg_set_in_bb);
+      reg_set_in_bb = NULL;
+    }
 }
 
 /* Returns nonzero if INSN's pattern has matching constraints for any operand.
@@ -1513,9 +1480,7 @@ regmove_optimize (f, nregs, regmove_dump_file)
    Initialize the info in MATCHP based on the constraints.  */
 
 static int
-find_matches (insn, matchp)
-     rtx insn;
-     struct match *matchp;
+find_matches (rtx insn, struct match *matchp)
 {
   int likely_spilled[MAX_RECOG_OPERANDS];
   int op_no;
@@ -1551,71 +1516,110 @@ find_matches (insn, matchp)
        if (*p == ',')
          i++;
 
-      while ((c = *p++) != '\0' && c != ',')
-       switch (c)
-         {
-         case '=':
-           break;
-         case '+':
-           break;
-         case '&':
-           matchp->early_clobber[op_no] = 1;
-           break;
-         case '%':
-           matchp->commutative[op_no] = op_no + 1;
-           matchp->commutative[op_no + 1] = op_no;
-           break;
-         case '0': case '1': case '2': case '3': case '4':
-         case '5': case '6': case '7': case '8': case '9':
-           c -= '0';
-           if (c < op_no && likely_spilled[(unsigned char) c])
+      while ((c = *p) != '\0' && c != ',')
+       {
+         switch (c)
+           {
+           case '=':
              break;
-           matchp->with[op_no] = c;
-           any_matches = 1;
-           if (matchp->commutative[op_no] >= 0)
-             matchp->with[matchp->commutative[op_no]] = c;
-           break;
+           case '+':
+             break;
+           case '&':
+             matchp->early_clobber[op_no] = 1;
+             break;
+           case '%':
+             matchp->commutative[op_no] = op_no + 1;
+             matchp->commutative[op_no + 1] = op_no;
+             break;
+
+           case '0': case '1': case '2': case '3': case '4':
+           case '5': case '6': case '7': case '8': case '9':
+             {
+               char *end;
+               unsigned long match_ul = strtoul (p, &end, 10);
+               int match = match_ul;
+
+               p = end;
+
+               if (match < op_no && likely_spilled[match])
+                 continue;
+               matchp->with[op_no] = match;
+               any_matches = 1;
+               if (matchp->commutative[op_no] >= 0)
+                 matchp->with[matchp->commutative[op_no]] = match;
+             }
+           continue;
+
          case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h':
          case 'j': case 'k': case 'l': case 'p': case 'q': case 't': case 'u':
          case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
          case 'C': case 'D': case 'W': case 'Y': case 'Z':
-           if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_LETTER ((unsigned char)c)))
+           if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p) ))
              likely_spilled[op_no] = 1;
            break;
          }
+         p += CONSTRAINT_LEN (c, p);
+       }
     }
   return any_matches;
 }
 
+/* Try to replace all occurrences of DST_REG with SRC in LOC, that is
+   assumed to be in INSN.  */
+
+static void
+replace_in_call_usage (rtx *loc, unsigned int dst_reg, rtx src, rtx insn)
+{
+  rtx x = *loc;
+  enum rtx_code code;
+  const char *fmt;
+  int i, j;
+
+  if (! x)
+    return;
+
+  code = GET_CODE (x);
+  if (code == REG)
+    {
+      if (REGNO (x) != dst_reg)
+       return;
+
+      validate_change (insn, loc, src, 1);
+
+      return;
+    }
+
+  /* Process each of our operands recursively.  */
+  fmt = GET_RTX_FORMAT (code);
+  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+    if (*fmt == 'e')
+      replace_in_call_usage (&XEXP (x, i), dst_reg, src, insn);
+    else if (*fmt == 'E')
+      for (j = 0; j < XVECLEN (x, i); j++)
+       replace_in_call_usage (& XVECEXP (x, i, j), dst_reg, src, insn);
+}
+
 /* Try to replace output operand DST in SET, with input operand SRC.  SET is
    the only set in INSN.  INSN has just been recognized and constrained.
    SRC is operand number OPERAND_NUMBER in INSN.
    DST is operand number MATCH_NUMBER in INSN.
    If BACKWARD is nonzero, we have been called in a backward pass.
    Return nonzero for success.  */
+
 static int
-fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
-              match_number, regmove_dump_file)
-     rtx insn, set, src, src_subreg, dst;
-     int backward, operand_number, match_number;
-     FILE *regmove_dump_file;
+fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst,
+              int backward, int operand_number, int match_number)
 {
   rtx p;
   rtx post_inc = 0, post_inc_set = 0, search_end = 0;
   int success = 0;
   int num_calls = 0, s_num_calls = 0;
   enum rtx_code code = NOTE;
-  HOST_WIDE_INT insn_const = 0, newconst;
+  HOST_WIDE_INT insn_const = 0, newconst = 0;
   rtx overlap = 0; /* need to move insn ? */
   rtx src_note = find_reg_note (insn, REG_DEAD, src), dst_note = NULL_RTX;
   int length, s_length;
 
-  /* If SRC is marked as unchanging, we may not change it.
-     ??? Maybe we could get better code by removing the unchanging bit
-     instead, and changing it back if we don't succeed?  */
-  if (RTX_UNCHANGING_P (src))
-    return 0;
-
   if (! src_note)
     {
       /* Look for (set (regX) (op regA constX))
@@ -1639,8 +1643,8 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
        code = NOTE;
     }
 
-  if (regmove_dump_file)
-    fprintf (regmove_dump_file,
+  if (dump_file)
+    fprintf (dump_file,
             "Could fix operand %d of insn %d matching operand %d.\n",
             operand_number, INSN_UID (insn), match_number);
 
@@ -1648,7 +1652,7 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
      then do not use it for this optimization.  We want the equivalence
      so that if we have to reload this register, we can reload the
      constant, rather than extending the lifespan of the register.  */
-  if (reg_is_remote_constant_p (src, insn, get_insns ()))
+  if (reg_is_remote_constant_p (src, insn))
     return 0;
 
   /* Scan forward to find the next instruction that
@@ -1658,18 +1662,15 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
 
   for (length = s_length = 0, p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
     {
-      if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
-       break;
+      if (CALL_P (p))
+       replace_in_call_usage (& CALL_INSN_FUNCTION_USAGE (p),
+                              REGNO (dst), src, p);
 
       /* ??? We can't scan past the end of a basic block without updating
-        the register lifetime info (REG_DEAD/basic_block_live_at_start).
-        A CALL_INSN might be the last insn of a basic block, if it is
-        inside an EH region.  There is no easy way to tell, so we just
-        always break when we see a CALL_INSN if flag_exceptions is nonzero.  */
-      if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+        the register lifetime info (REG_DEAD/basic_block_live_at_start).  */
+      if (perhaps_ends_bb_p (p))
        break;
-
-      if (! INSN_P (p))
+      else if (! INSN_P (p))
        continue;
 
       length++;
@@ -1704,29 +1705,18 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
                break;
              for (q = p; q; q = NEXT_INSN (q))
                {
-                 if (GET_CODE (q) == CODE_LABEL || GET_CODE (q) == JUMP_INSN)
-                   {
-                     q = 0;
-                     break;
-                   }
-
                  /* ??? We can't scan past the end of a basic block without
                     updating the register lifetime info
-                    (REG_DEAD/basic_block_live_at_start).
-                    A CALL_INSN might be the last insn of a basic block, if
-                    it is inside an EH region.  There is no easy way to tell,
-                    so we just always break when we see a CALL_INSN if
-                    flag_exceptions is nonzero.  */
-                 if (flag_exceptions && GET_CODE (q) == CALL_INSN)
+                    (REG_DEAD/basic_block_live_at_start).  */
+                 if (perhaps_ends_bb_p (q))
                    {
                      q = 0;
                      break;
                    }
-
-                 if (! INSN_P (q))
+                 else if (! INSN_P (q))
                    continue;
-                 if (reg_overlap_mentioned_p (src, PATTERN (q))
-                     || reg_set_p (src, q))
+                 else if (reg_overlap_mentioned_p (src, PATTERN (q))
+                          || reg_set_p (src, q))
                    break;
                }
              if (q)
@@ -1749,7 +1739,7 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
                         hard register.  */
                      && ! (dst_note && ! REG_N_CALLS_CROSSED (REGNO (dst))
                            && single_set (p)
-                           && GET_CODE (SET_DEST (single_set (p))) == REG
+                           && REG_P (SET_DEST (single_set (p)))
                            && (REGNO (SET_DEST (single_set (p)))
                                < FIRST_PSEUDO_REGISTER))
                      /* We may only emit an insn directly after P if we
@@ -1771,8 +1761,9 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
                  /* Reject out of range shifts.  */
                  if (code != PLUS
                      && (newconst < 0
-                         || (newconst
-                             >= GET_MODE_BITSIZE (GET_MODE (SET_SRC (set2))))))
+                         || ((unsigned HOST_WIDE_INT) newconst
+                             >= (GET_MODE_BITSIZE (GET_MODE
+                                                   (SET_SRC (set2)))))))
                    break;
                  if (code == PLUS)
                    {
@@ -1808,7 +1799,7 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
 
       /* If we have passed a call instruction, and the pseudo-reg SRC is not
         already live across a call, then don't perform the optimization.  */
-      if (GET_CODE (p) == CALL_INSN)
+      if (CALL_P (p))
        {
          if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
            break;
@@ -1852,17 +1843,9 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
        {
          rtx notes = REG_NOTES (insn);
 
-         emit_insn_after_with_line_notes (pat, PREV_INSN (p), insn);
-         PUT_CODE (insn, NOTE);
-         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-         NOTE_SOURCE_FILE (insn) = 0;
-         /* emit_insn_after_with_line_notes has no
-            return value, so search for the new insn.  */
-         insn = p;
-         while (! INSN_P (insn) || PATTERN (insn) != pat)
-           insn = PREV_INSN (insn);
-
-         REG_NOTES (insn) = notes;
+         p = emit_insn_after_setloc (pat, PREV_INSN (p), INSN_LOCATOR (insn));
+         delete_insn (insn);
+         REG_NOTES (p) = notes;
        }
     }
   /* Sometimes we'd generate src = const; src += n;
@@ -1877,29 +1860,19 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
 
       if (note && CONSTANT_P (XEXP (note, 0)))
        {
-         for (q = PREV_INSN (insn); q; q = PREV_INSN(q))
+         for (q = PREV_INSN (insn); q; q = PREV_INSN (q))
            {
-             if (GET_CODE (q) == CODE_LABEL || GET_CODE (q) == JUMP_INSN)
-               {
-                 q = 0;
-                 break;
-               }
-
              /* ??? We can't scan past the end of a basic block without
                 updating the register lifetime info
-                (REG_DEAD/basic_block_live_at_start).
-                A CALL_INSN might be the last insn of a basic block, if
-                it is inside an EH region.  There is no easy way to tell,
-                so we just always break when we see a CALL_INSN if
-                flag_exceptions is nonzero.  */
-             if (flag_exceptions && GET_CODE (q) == CALL_INSN)
+                (REG_DEAD/basic_block_live_at_start).  */
+             if (perhaps_ends_bb_p (q))
                {
                  q = 0;
                  break;
                }
-
-             if (! INSN_P (q))
+             else if (! INSN_P (q))
                continue;
+
              s_length2++;
              if (reg_set_p (src, q))
                {
@@ -1911,15 +1884,13 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
                  q = 0;
                  break;
                }
-             if (GET_CODE (p) == CALL_INSN)
+             if (CALL_P (p))
                num_calls2++;
            }
          if (q && set2 && SET_DEST (set2) == src && CONSTANT_P (SET_SRC (set2))
              && validate_change (insn, &SET_SRC (set), XEXP (note, 0), 0))
            {
-             PUT_CODE (q, NOTE);
-             NOTE_LINE_NUMBER (q) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (q) = 0;
+             delete_insn (q);
              REG_N_SETS (REGNO (src))--;
              REG_N_CALLS_CROSSED (REGNO (src)) -= num_calls2;
              REG_LIVE_LENGTH (REGNO (src)) -= s_length2;
@@ -1951,26 +1922,20 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
       inc_dest = post_inc_set ? SET_DEST (post_inc_set) : src;
       for (q = post_inc; (q = NEXT_INSN (q)); )
        {
-         if (GET_CODE (q) == CODE_LABEL || GET_CODE (q) == JUMP_INSN)
-           break;
-
          /* ??? We can't scan past the end of a basic block without updating
-            the register lifetime info (REG_DEAD/basic_block_live_at_start).
-            A CALL_INSN might be the last insn of a basic block, if it
-            is inside an EH region.  There is no easy way to tell so we
-            just always break when we see a CALL_INSN if flag_exceptions
-            is nonzero.  */
-         if (flag_exceptions && GET_CODE (q) == CALL_INSN)
+            the register lifetime info
+            (REG_DEAD/basic_block_live_at_start).  */
+         if (perhaps_ends_bb_p (q))
            break;
-
-         if (! INSN_P (q))
+         else if (! INSN_P (q))
            continue;
-         if (src != inc_dest && (reg_overlap_mentioned_p (src, PATTERN (q))
-                                 || reg_set_p (src, q)))
+         else if (src != inc_dest
+                  && (reg_overlap_mentioned_p (src, PATTERN (q))
+                      || reg_set_p (src, q)))
            break;
-         if (reg_set_p (inc_dest, q))
+         else if (reg_set_p (inc_dest, q))
            break;
-         if (reg_overlap_mentioned_p (inc_dest, PATTERN (q)))
+         else if (reg_overlap_mentioned_p (inc_dest, PATTERN (q)))
            {
              try_auto_increment (q, post_inc,
                                  post_inc_set, inc_dest, newconst, 1);
@@ -1978,6 +1943,7 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
            }
        }
     }
+
   /* Move the death note for DST to INSN if it is used
      there.  */
   if (reg_overlap_mentioned_p (dst, PATTERN (insn)))
@@ -2012,30 +1978,32 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
       if (REG_LIVE_LENGTH (REGNO (dst)) < 2)
        REG_LIVE_LENGTH (REGNO (dst)) = 2;
     }
-  if (regmove_dump_file)
-    fprintf (regmove_dump_file,
+  if (dump_file)
+    fprintf (dump_file,
             "Fixed operand %d of insn %d matching operand %d.\n",
             operand_number, INSN_UID (insn), match_number);
   return 1;
 }
 
 
-/* return nonzero if X is stable and mentions no regsiters but for
+/* Return nonzero if X is stable and mentions no registers but for
    mentioning SRC or mentioning / changing DST .  If in doubt, presume
    it is unstable.
    The rationale is that we want to check if we can move an insn easily
-   while just paying attention to SRC and DST.  A register is considered
-   stable if it has the RTX_UNCHANGING_P bit set, but that would still
-   leave the burden to update REG_DEAD / REG_UNUSED notes, so we don't
-   want any registers but SRC and DST.  */
+   while just paying attention to SRC and DST.  */
 static int
-stable_and_no_regs_but_for_p (x, src, dst)
-     rtx x, src, dst;
+stable_and_no_regs_but_for_p (rtx x, rtx src, rtx dst)
 {
   RTX_CODE code = GET_CODE (x);
   switch (GET_RTX_CLASS (code))
     {
-    case '<': case '1': case 'c': case '2': case 'b': case '3':
+    case RTX_UNARY:
+    case RTX_BIN_ARITH:
+    case RTX_COMM_ARITH:
+    case RTX_COMPARE:
+    case RTX_COMM_COMPARE:
+    case RTX_TERNARY:
+    case RTX_BITFIELD_OPS:
       {
        int i;
        const char *fmt = GET_RTX_FORMAT (code);
@@ -2045,7 +2013,7 @@ stable_and_no_regs_but_for_p (x, src, dst)
              return 0;
        return 1;
       }
-    case 'o':
+    case RTX_OBJ:
       if (code == REG)
        return x == src || x == dst;
       /* If this is a MEM, look inside - there might be a register hidden in
@@ -2053,395 +2021,44 @@ stable_and_no_regs_but_for_p (x, src, dst)
       if (code == MEM
          && ! stable_and_no_regs_but_for_p (XEXP (x, 0), src, dst))
        return 0;
-      /* fall through */
+      /* Fall through.  */
     default:
       return ! rtx_unstable_p (x);
     }
 }
 \f
-/* Track stack adjustments and stack memory references.  Attempt to 
-   reduce the number of stack adjustments by back-propogating across
-   the memory references.
-
-   This is intended primarily for use with targets that do not define
-   ACCUMULATE_OUTGOING_ARGS.  It is of significantly more value to
-   targets that define PREFERRED_STACK_BOUNDARY more aligned than
-   STACK_BOUNDARY (e.g. x86), or if not all registers can be pushed
-   (e.g. x86 fp regs) which would ordinarily have to be implemented
-   as a sub/mov pair due to restrictions in calls.c.
-
-   Propogation stops when any of the insns that need adjusting are
-   (a) no longer valid because we've exceeded their range, (b) a
-   non-trivial push instruction, or (c) a call instruction.
-
-   Restriction B is based on the assumption that push instructions
-   are smaller or faster.  If a port really wants to remove all
-   pushes, it should have defined ACCUMULATE_OUTGOING_ARGS.  The
-   one exception that is made is for an add immediately followed
-   by a push.  */
-
-/* This structure records stack memory references between stack adjusting
-   instructions.  */
-
-struct csa_memlist
-{
-  HOST_WIDE_INT sp_offset;
-  rtx insn, *mem;
-  struct csa_memlist *next;
-};
-
-static int stack_memref_p              PARAMS ((rtx));
-static rtx single_set_for_csa          PARAMS ((rtx));
-static void free_csa_memlist           PARAMS ((struct csa_memlist *));
-static struct csa_memlist *record_one_stack_memref
-  PARAMS ((rtx, rtx *, struct csa_memlist *));
-static int try_apply_stack_adjustment
-  PARAMS ((rtx, struct csa_memlist *, HOST_WIDE_INT, HOST_WIDE_INT));
-static void combine_stack_adjustments_for_block PARAMS ((basic_block));
-static int record_stack_memrefs        PARAMS ((rtx *, void *));
 
-
-/* Main entry point for stack adjustment combination.  */
-
-void
-combine_stack_adjustments ()
+static bool
+gate_handle_regmove (void)
 {
-  int i;
-
-  for (i = 0; i < n_basic_blocks; ++i)
-    combine_stack_adjustments_for_block (BASIC_BLOCK (i));
+  return (optimize > 0 && flag_regmove);
 }
 
-/* Recognize a MEM of the form (sp) or (plus sp const).  */
-
-static int
-stack_memref_p (x)
-     rtx x;
+/* Register allocation pre-pass, to reduce number of moves necessary
+   for two-address machines.  */
+static unsigned int
+rest_of_handle_regmove (void)
 {
-  if (GET_CODE (x) != MEM)
-    return 0;
-  x = XEXP (x, 0);
-
-  if (x == stack_pointer_rtx)
-    return 1;
-  if (GET_CODE (x) == PLUS
-      && XEXP (x, 0) == stack_pointer_rtx
-      && GET_CODE (XEXP (x, 1)) == CONST_INT)
-    return 1;
-
+  regmove_optimize (get_insns (), max_reg_num ());
+  cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
   return 0;
 }
 
-/* Recognize either normal single_set or the hack in i386.md for
-   tying fp and sp adjustments.  */
-
-static rtx
-single_set_for_csa (insn)
-     rtx insn;
-{
-  int i;
-  rtx tmp = single_set (insn);
-  if (tmp)
-    return tmp;
-
-  if (GET_CODE (insn) != INSN
-      || GET_CODE (PATTERN (insn)) != PARALLEL)
-    return NULL_RTX;
-
-  tmp = PATTERN (insn);
-  if (GET_CODE (XVECEXP (tmp, 0, 0)) != SET)
-    return NULL_RTX;
-
-  for (i = 1; i < XVECLEN (tmp, 0); ++i)
-    {
-      rtx this = XVECEXP (tmp, 0, i);
-
-      /* The special case is allowing a no-op set.  */
-      if (GET_CODE (this) == SET
-         && SET_SRC (this) == SET_DEST (this))
-       ;
-      else if (GET_CODE (this) != CLOBBER
-              && GET_CODE (this) != USE)
-       return NULL_RTX;
-    }
-
-  return XVECEXP (tmp, 0, 0);
-}
-
-/* Free the list of csa_memlist nodes.  */
-
-static void
-free_csa_memlist (memlist)
-     struct csa_memlist *memlist;
-{
-  struct csa_memlist *next;
-  for (; memlist ; memlist = next)
-    {
-      next = memlist->next;
-      free (memlist);
-    }
-}
-
-/* Create a new csa_memlist node from the given memory reference.
-   It is already known that the memory is stack_memref_p.  */
-
-static struct csa_memlist *
-record_one_stack_memref (insn, mem, next_memlist)
-     rtx insn, *mem;
-     struct csa_memlist *next_memlist;
-{
-  struct csa_memlist *ml;
-
-  ml = (struct csa_memlist *) xmalloc (sizeof (*ml));
-
-  if (XEXP (*mem, 0) == stack_pointer_rtx)
-    ml->sp_offset = 0;
-  else
-    ml->sp_offset = INTVAL (XEXP (XEXP (*mem, 0), 1));
-
-  ml->insn = insn;
-  ml->mem = mem;
-  ml->next = next_memlist;
-
-  return ml;
-}
-
-/* Attempt to apply ADJUST to the stack adjusting insn INSN, as well
-   as each of the memories in MEMLIST.  Return true on success.  */
-
-static int
-try_apply_stack_adjustment (insn, memlist, new_adjust, delta)
-     rtx insn;
-     struct csa_memlist *memlist;
-     HOST_WIDE_INT new_adjust, delta;
-{
-  struct csa_memlist *ml;
-  rtx set;
-
-  /* We know INSN matches single_set_for_csa, because that's what we
-     recognized earlier.  However, if INSN is not single_set, it is
-     doing double duty as a barrier for frame pointer memory accesses,
-     which we are not recording.  Therefore, an adjust insn that is not
-     single_set may not have a positive delta applied.  */
-
-  if (delta > 0 && ! single_set (insn))
-    return 0;
-  set = single_set_for_csa (insn);
-  validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);
-
-  for (ml = memlist; ml ; ml = ml->next)
-    {
-      HOST_WIDE_INT c = ml->sp_offset - delta;
-      rtx new = gen_rtx_MEM (GET_MODE (*ml->mem),
-                            plus_constant (stack_pointer_rtx, c));
-
-      /* Don't reference memory below the stack pointer.  */
-      if (c < 0)
-       {
-         cancel_changes (0);
-         return 0;
-       }
-
-      MEM_COPY_ATTRIBUTES (new, *ml->mem);
-      validate_change (ml->insn, ml->mem, new, 1);
-    }
-
-  if (apply_change_group ())
-    {
-      /* Succeeded.  Update our knowledge of the memory references.  */
-      for (ml = memlist; ml ; ml = ml->next)
-       ml->sp_offset -= delta;
-
-      return 1;
-    }
-  else
-    return 0;
-}
-
-/* Called via for_each_rtx and used to record all stack memory references in
-   the insn and discard all other stack pointer references.  */
-struct record_stack_memrefs_data
+struct tree_opt_pass pass_regmove =
 {
-  rtx insn;
-  struct csa_memlist *memlist;
+  "regmove",                            /* name */
+  gate_handle_regmove,                  /* gate */
+  rest_of_handle_regmove,               /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_REGMOVE,                           /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  'N'                                   /* letter */
 };
 
-static int
-record_stack_memrefs (xp, data)
-     rtx *xp;
-     void *data;
-{
-  rtx x = *xp;
-  struct record_stack_memrefs_data *d =
-    (struct record_stack_memrefs_data *) data;
-  if (!x)
-    return 0;
-  switch (GET_CODE (x))
-    {
-    case MEM:
-      if (!reg_mentioned_p (stack_pointer_rtx, x))
-       return -1;
-      /* We are not able to handle correctly all possible memrefs containing
-         stack pointer, so this check is neccesary.  */
-      if (stack_memref_p (x))
-       {
-         d->memlist = record_one_stack_memref (d->insn, xp, d->memlist);
-         return -1;
-       }
-      return 1;
-    case REG:
-      /* ??? We want be able to handle non-memory stack pointer references
-         later.  For now just discard all insns refering to stack pointer
-         outside mem expressions.  We would probably want to teach
-        validate_replace to simplify expressions first.  */
-      if (x == stack_pointer_rtx)
-       return 1;
-      break;
-    default:
-      break;
-    }
-  return 0;
-}
-
-/* Subroutine of combine_stack_adjustments, called for each basic block.  */
-
-static void 
-combine_stack_adjustments_for_block (bb)
-     basic_block bb;
-{
-  HOST_WIDE_INT last_sp_adjust = 0;
-  rtx last_sp_set = NULL_RTX;
-  struct csa_memlist *memlist = NULL;
-  rtx pending_delete;
-  rtx insn, next;
-  struct record_stack_memrefs_data data;
-
-  for (insn = bb->head; ; insn = next)
-    {
-      rtx set;
-
-      pending_delete = NULL_RTX;
-      next = NEXT_INSN (insn);
-
-      if (! INSN_P (insn))
-       goto processed;
-
-      set = single_set_for_csa (insn);
-      if (set)
-       {
-         rtx dest = SET_DEST (set);
-         rtx src = SET_SRC (set);
-
-         /* Find constant additions to the stack pointer.  */
-         if (dest == stack_pointer_rtx
-             && GET_CODE (src) == PLUS
-             && XEXP (src, 0) == stack_pointer_rtx
-             && GET_CODE (XEXP (src, 1)) == CONST_INT)
-           {
-             HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));
-
-             /* If we've not seen an adjustment previously, record
-                it now and continue.  */
-             if (! last_sp_set)
-               {
-                 last_sp_set = insn;
-                 last_sp_adjust = this_adjust;
-                 goto processed;
-               }
-
-             /* If not all recorded memrefs can be adjusted, or the
-                adjustment is now too large for a constant addition,
-                we cannot merge the two stack adjustments.  */
-             if (! try_apply_stack_adjustment (last_sp_set, memlist,
-                                               last_sp_adjust + this_adjust,
-                                               this_adjust))
-               {
-                 free_csa_memlist (memlist);
-                 memlist = NULL;
-                 last_sp_set = insn;
-                 last_sp_adjust = this_adjust;
-                 goto processed;
-               }
-
-             /* It worked!  */
-             pending_delete = insn;
-             last_sp_adjust += this_adjust;
-
-             /* If, by some accident, the adjustments cancel out,
-                delete both insns and start from scratch.  */
-             if (last_sp_adjust == 0)
-               {
-                 if (last_sp_set == bb->head)
-                   bb->head = NEXT_INSN (last_sp_set);
-                 flow_delete_insn (last_sp_set);
-
-                 free_csa_memlist (memlist);
-                 memlist = NULL;
-                 last_sp_set = NULL_RTX;
-               }
-
-             goto processed;
-           }
-
-         /* Find a predecrement of exactly the previous adjustment and
-            turn it into a direct store.  Obviously we can't do this if
-            there were any intervening uses of the stack pointer.  */
-         if (memlist == NULL
-             && last_sp_adjust == GET_MODE_SIZE (GET_MODE (dest))
-             && GET_CODE (dest) == MEM
-             && GET_CODE (XEXP (dest, 0)) == PRE_DEC
-             && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
-             && ! reg_mentioned_p (stack_pointer_rtx, src)
-             && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
-             && validate_change (insn, &SET_DEST (set),
-                                 change_address (dest, VOIDmode,
-                                                 stack_pointer_rtx), 0))
-           {
-             if (last_sp_set == bb->head)
-               bb->head = NEXT_INSN (last_sp_set);
-             flow_delete_insn (last_sp_set);
-
-             free_csa_memlist (memlist);
-             memlist = NULL;
-             last_sp_set = NULL_RTX;
-             last_sp_adjust = 0;
-             goto processed;
-           }
-       }
-
-      data.insn = insn;
-      data.memlist = memlist;
-      if (GET_CODE (insn) != CALL_INSN && last_sp_set
-         && !for_each_rtx (&PATTERN (insn), record_stack_memrefs, &data))
-       {
-          memlist = data.memlist;
-          goto processed;
-       }
-      memlist = data.memlist;
-
-      /* Otherwise, we were not able to process the instruction. 
-        Do not continue collecting data across such a one.  */
-      if (last_sp_set
-         && (GET_CODE (insn) == CALL_INSN
-             || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
-       {
-         free_csa_memlist (memlist);
-         memlist = NULL;
-         last_sp_set = NULL_RTX;
-         last_sp_adjust = 0;
-       }
-
-    processed:
-      if (insn == bb->end)
-       break;
-
-      if (pending_delete)
-       flow_delete_insn (pending_delete);
-    }
-
-  if (pending_delete)
-    {
-      bb->end = PREV_INSN (pending_delete);
-      flow_delete_insn (pending_delete);
-    }
-}