OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / regmove.c
index d874695..454c977 100644 (file)
@@ -1,12 +1,13 @@
 /* Move registers around to reduce number of move instructions needed.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
 /* Move registers around to reduce number of move instructions needed.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 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
 
 This file is part of GCC.
 
 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
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,24 +16,22 @@ 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
 for more details.
 
 You should have received a copy of the GNU General Public License
-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.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 
 
 
-/* This module looks for cases where matching constraints would force
-   an instruction to need a reload, and this reload would be a register
-   to register move.  It then attempts to change the registers used by the
-   instruction to avoid the move instruction.  */
+/* This module makes some simple RTL code transformations which
+   improve the subsequent register allocation.  */
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "rtl.h" /* stdio.h must precede rtl.h for FFS.  */
+#include "rtl.h"
 #include "tm_p.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "tm_p.h"
 #include "insn-config.h"
 #include "recog.h"
+#include "target.h"
 #include "output.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "output.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -41,59 +40,116 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "expr.h"
 #include "basic-block.h"
 #include "except.h"
 #include "expr.h"
 #include "basic-block.h"
 #include "except.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "reload.h"
 #include "timevar.h"
 #include "tree-pass.h"
 #include "reload.h"
 #include "timevar.h"
 #include "tree-pass.h"
+#include "df.h"
+#include "ira.h"
 
 
-
-/* Turn STACK_GROWS_DOWNWARD into a boolean.  */
-#ifdef STACK_GROWS_DOWNWARD
-#undef STACK_GROWS_DOWNWARD
-#define STACK_GROWS_DOWNWARD 1
-#else
-#define STACK_GROWS_DOWNWARD 0
-#endif
-
-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 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, int);
-static int *regmove_bb_head;
+static void copy_src_to_dest (rtx, rtx, rtx);
+
+enum match_use
+{
+  READ,
+  WRITE,
+  READWRITE
+};
 
 struct match {
   int with[MAX_RECOG_OPERANDS];
 
 struct match {
   int with[MAX_RECOG_OPERANDS];
-  enum { READ, WRITE, READWRITE } use[MAX_RECOG_OPERANDS];
+  enum match_use use[MAX_RECOG_OPERANDS];
   int commutative[MAX_RECOG_OPERANDS];
   int early_clobber[MAX_RECOG_OPERANDS];
 };
 
   int commutative[MAX_RECOG_OPERANDS];
   int early_clobber[MAX_RECOG_OPERANDS];
 };
 
-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 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
 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 (int class0, int class1)
+regclass_compatible_p (reg_class_t class0, reg_class_t class1)
 {
   return (class0 == class1
          || (reg_class_subset_p (class0, class1)
 {
   return (class0 == class1
          || (reg_class_subset_p (class0, class1)
-             && ! CLASS_LIKELY_SPILLED_P (class0))
+             && ! targetm.class_likely_spilled_p (class0))
          || (reg_class_subset_p (class1, class0)
          || (reg_class_subset_p (class1, class0)
-             && ! CLASS_LIKELY_SPILLED_P (class1)));
+             && ! targetm.class_likely_spilled_p (class1)));
 }
 
 }
 
+\f
+#ifdef AUTO_INC_DEC
+
+/* Find the place in the rtx X where REG is used as a memory address.
+   Return the MEM rtx that so uses it.
+   If PLUSCONST is nonzero, search instead for a memory address equivalent to
+   (plus REG (const_int PLUSCONST)).
+
+   If such an address does not appear, return 0.
+   If REG appears more than once, or is used other than in such an address,
+   return (rtx) 1.  */
+
+static rtx
+find_use_as_address (rtx x, rtx reg, HOST_WIDE_INT plusconst)
+{
+  enum rtx_code code = GET_CODE (x);
+  const char * const fmt = GET_RTX_FORMAT (code);
+  int i;
+  rtx value = 0;
+  rtx tem;
+
+  if (code == MEM && XEXP (x, 0) == reg && plusconst == 0)
+    return x;
+
+  if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS
+      && XEXP (XEXP (x, 0), 0) == reg
+      && CONST_INT_P (XEXP (XEXP (x, 0), 1))
+      && INTVAL (XEXP (XEXP (x, 0), 1)) == plusconst)
+    return x;
+
+  if (code == SIGN_EXTRACT || code == ZERO_EXTRACT)
+    {
+      /* If REG occurs inside a MEM used in a bit-field reference,
+        that is unacceptable.  */
+      if (find_use_as_address (XEXP (x, 0), reg, 0) != 0)
+       return (rtx) (size_t) 1;
+    }
+
+  if (x == reg)
+    return (rtx) (size_t) 1;
+
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       {
+         tem = find_use_as_address (XEXP (x, i), reg, plusconst);
+         if (value == 0)
+           value = tem;
+         else if (tem != 0)
+           return (rtx) (size_t) 1;
+       }
+      else if (fmt[i] == 'E')
+       {
+         int j;
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+           {
+             tem = find_use_as_address (XVECEXP (x, i, j), reg, plusconst);
+             if (value == 0)
+               value = tem;
+             else if (tem != 0)
+               return (rtx) (size_t) 1;
+           }
+       }
+    }
+
+  return value;
+}
+
+
 /* 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.
 /* 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.
@@ -130,22 +186,23 @@ try_auto_increment (rtx insn, rtx inc_insn, rtx inc_insn_set, rtx reg,
                   &SET_SRC (inc_insn_set),
                   XEXP (SET_SRC (inc_insn_set), 0), 1);
              validate_change (insn, &XEXP (use, 0),
                   &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);
+                              gen_rtx_fmt_e (inc_code,
+                                             GET_MODE (XEXP (use, 0)), 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
              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
+                    result in sched1 dying -- 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)
                     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);
+                   PUT_REG_NOTE_KIND (note, REG_UNUSED);
+
+                 add_reg_note (insn, REG_INC, reg);
 
 
-                 REG_NOTES (insn)
-                   = gen_rtx_EXPR_LIST (REG_INC,
-                                        reg, REG_NOTES (insn));
                  if (! inc_insn_set)
                    delete_insn (inc_insn);
                  return 1;
                  if (! inc_insn_set)
                    delete_insn (inc_insn);
                  return 1;
@@ -155,233 +212,11 @@ try_auto_increment (rtx insn, rtx inc_insn, rtx inc_insn_set, rtx reg,
     }
   return 0;
 }
     }
   return 0;
 }
-\f
-/* Determine if the pattern generated by add_optab has a clobber,
-   such as might be issued for a flags hard register.  To make the
-   code elsewhere simpler, we handle cc0 in this same framework.
-
-   Return the register if one was discovered.  Return NULL_RTX if
-   if no flags were found.  Return pc_rtx if we got confused.  */
-
-static rtx
-discover_flags_reg (void)
-{
-  rtx tmp;
-  tmp = gen_rtx_REG (word_mode, 10000);
-  tmp = gen_add3_insn (tmp, tmp, const2_rtx);
-
-  /* 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;
-  else if (GET_CODE (tmp) == PARALLEL)
-    {
-      int found;
-
-      if (XVECLEN (tmp, 0) != 2)
-       return pc_rtx;
-      tmp = XVECEXP (tmp, 0, 1);
-      if (GET_CODE (tmp) != CLOBBER)
-       return pc_rtx;
-      tmp = XEXP (tmp, 0);
-
-      /* Don't do anything foolish if the md wanted to clobber a
-        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
-         && REG_P (SUBREG_REG (tmp))
-         && REGNO (SUBREG_REG (tmp)) < FIRST_PSEUDO_REGISTER)
-       return pc_rtx;
-      found = (REG_P (tmp) && REGNO (tmp) < FIRST_PSEUDO_REGISTER);
-
-      return (found ? tmp : NULL_RTX);
-    }
-
-  return pc_rtx;
-}
-
-/* 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 --
-
-   QImode is used on the instruction at which the flags becomes live.
-
-   HImode is used within the range (exclusive) that the flags are
-   live.  Thus the user of the flags is not marked.
-
-   All other instructions are cleared to VOIDmode.  */
-
-/* Used to communicate with flags_set_1.  */
-static rtx flags_set_1_rtx;
-static int flags_set_1_set;
-
-static void
-mark_flags_life_zones (rtx flags)
-{
-  int flags_regno;
-  int flags_nregs;
-  basic_block block;
-
-#ifdef HAVE_cc0
-  /* If we found a flags register on a cc0 host, bail.  */
-  if (flags == NULL_RTX)
-    flags = cc0_rtx;
-  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))
-       PUT_MODE (insn, mode);
-      return;
-    }
-
-#ifdef HAVE_cc0
-  flags_regno = -1;
-  flags_nregs = 1;
-#else
-  flags_regno = REGNO (flags);
-  flags_nregs = hard_regno_nregs[flags_regno][GET_MODE (flags)];
-#endif
-  flags_set_1_rtx = flags;
-
-  /* Process each basic block.  */
-  FOR_EACH_BB_REVERSE (block)
-    {
-      rtx insn, end;
-      int live;
-
-      insn = BB_HEAD (block);
-      end = BB_END (block);
-
-      /* Look out for the (unlikely) case of flags being live across
-        basic block boundaries.  */
-      live = 0;
-#ifndef HAVE_cc0
-      {
-       int i;
-       for (i = 0; i < flags_nregs; ++i)
-         live |= REGNO_REG_SET_P (block->il.rtl->global_live_at_start,
-                                  flags_regno + i);
-      }
-#endif
-
-      while (1)
-       {
-         /* Process liveness in reverse order of importance --
-            alive, death, birth.  This lets more important info
-            overwrite the mode of lesser info.  */
-
-         if (INSN_P (insn))
-           {
-#ifdef HAVE_cc0
-             /* In the cc0 case, death is not marked in reg notes,
-                but is instead the mere use of cc0 when it is alive.  */
-             if (live && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
-               live = 0;
-#else
-             /* In the hard reg case, we watch death notes.  */
-             if (live && find_regno_note (insn, REG_DEAD, flags_regno))
-               live = 0;
 #endif
 #endif
-             PUT_MODE (insn, (live ? HImode : VOIDmode));
 
 
-             /* 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);
-             if (flags_set_1_set)
-               {
-                 live = 1;
-                 PUT_MODE (insn, QImode);
-               }
-           }
-         else
-           PUT_MODE (insn, (live ? HImode : VOIDmode));
-
-         if (insn == end)
-           break;
-         insn = NEXT_INSN (insn);
-       }
-    }
-}
-
-/* A subroutine of mark_flags_life_zones, called through note_stores.  */
-
-static void
-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))
-    flags_set_1_set = 1;
-}
 \f
 static int *regno_src_regno;
 
 \f
 static int *regno_src_regno;
 
-/* Indicate how good a choice REG (which appears as a source) is to replace
-   a destination register with.  The higher the returned value, the better
-   the choice.  The main objective is to avoid using a register that is
-   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 (rtx reg)
-{
-  int src_regno;
-
-  /* Bad if this isn't a register at all.  */
-  if (!REG_P (reg))
-    return 0;
-
-  /* If this register is not meant to get a hard register,
-     it is a poor choice.  */
-  if (REG_LIVE_LENGTH (REGNO (reg)) < 0)
-    return 0;
-
-  src_regno = regno_src_regno[REGNO (reg)];
-
-  /* If it was not copied from another register, it is fine.  */
-  if (src_regno < 0)
-    return 3;
-
-  /* Copied from a hard register?  */
-  if (src_regno < FIRST_PSEUDO_REGISTER)
-    return 1;
-
-  /* Copied from a pseudo register - not as bad as from a hard register,
-     yet still cumbersome, since the register live length will be lengthened
-     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.
 
 /* INSN is a copy from SRC to DEST, both registers, and SRC does not die
    in INSN.
 
@@ -401,10 +236,11 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
   rtx dest_death = 0;
   int sregno = REGNO (src);
   int dregno = REGNO (dest);
   rtx dest_death = 0;
   int sregno = REGNO (src);
   int dregno = REGNO (dest);
+  basic_block bb = BLOCK_FOR_INSN (insn);
 
   /* We don't want to mess with hard regs if register classes are small.  */
   if (sregno == dregno
 
   /* We don't want to mess with hard regs if register classes are small.  */
   if (sregno == dregno
-      || (SMALL_REGISTER_CLASSES
+      || (targetm.small_register_classes_for_mode_p (GET_MODE (src))
          && (sregno < FIRST_PSEUDO_REGISTER
              || dregno < FIRST_PSEUDO_REGISTER))
       /* We don't see all updates to SP if they are in an auto-inc memory
          && (sregno < FIRST_PSEUDO_REGISTER
              || dregno < FIRST_PSEUDO_REGISTER))
       /* We don't see all updates to SP if they are in an auto-inc memory
@@ -414,12 +250,10 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
 
   for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
     {
 
   for (p = NEXT_INSN (insn); p; p = NEXT_INSN (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).  */
-      if (perhaps_ends_bb_p (p))
-       break;
-      else if (! INSN_P (p))
+      if (! INSN_P (p))
        continue;
        continue;
+      if (BLOCK_FOR_INSN (p) != bb)
+       break;
 
       if (reg_set_p (src, p) || reg_set_p (dest, p)
          /* If SRC is an asm-declared register, it must not be replaced
 
       if (reg_set_p (src, p) || reg_set_p (dest, p)
          /* If SRC is an asm-declared register, it must not be replaced
@@ -450,6 +284,8 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
          int s_length = 0;
          int d_n_calls = 0;
          int s_n_calls = 0;
          int s_length = 0;
          int d_n_calls = 0;
          int s_n_calls = 0;
+         int s_freq_calls = 0;
+         int d_freq_calls = 0;
 
          /* We can do the optimization.  Scan forward from INSN again,
             replacing regs as we go.  Set FAILED if a replacement can't
 
          /* We can do the optimization.  Scan forward from INSN again,
             replacing regs as we go.  Set FAILED if a replacement can't
@@ -471,7 +307,7 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
                  if (sregno < FIRST_PSEUDO_REGISTER
                      && reg_mentioned_p (dest, PATTERN (q)))
                    failed = 1;
                  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;
                  /* Attempt to replace all uses.  */
                  else if (!validate_replace_rtx (src, dest, q))
                    failed = 1;
@@ -489,9 +325,12 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
              /* For SREGNO, count the total number of insns scanned.
                 For DREGNO, count the total number of insns scanned after
                 passing the death note for DREGNO.  */
              /* For SREGNO, count the total number of insns scanned.
                 For DREGNO, count the total number of insns scanned after
                 passing the death note for DREGNO.  */
-             s_length++;
-             if (dest_death)
-               d_length++;
+             if (!DEBUG_INSN_P (p))
+               {
+                 s_length++;
+                 if (dest_death)
+                   d_length++;
+               }
 
              /* 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 the insn in which SRC dies is a CALL_INSN, don't count it
                 as a call that has been crossed.  Otherwise, count it.  */
@@ -500,8 +339,12 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
                  /* Similarly, total calls for SREGNO, total calls beyond
                     the death note for DREGNO.  */
                  s_n_calls++;
                  /* Similarly, total calls for SREGNO, total calls beyond
                     the death note for DREGNO.  */
                  s_n_calls++;
+                 s_freq_calls += REG_FREQ_FROM_BB  (BLOCK_FOR_INSN (q));
                  if (dest_death)
                  if (dest_death)
-                   d_n_calls++;
+                   {
+                     d_n_calls++;
+                     d_freq_calls += REG_FREQ_FROM_BB  (BLOCK_FOR_INSN (q));
+                   }
                }
 
              /* If DEST dies here, remove the death note and save it for
                }
 
              /* If DEST dies here, remove the death note and save it for
@@ -534,6 +377,7 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
                    }
 
                  REG_N_CALLS_CROSSED (sregno) -= s_n_calls;
                    }
 
                  REG_N_CALLS_CROSSED (sregno) -= s_n_calls;
+                 REG_FREQ_CALLS_CROSSED (sregno) -= s_freq_calls;
                }
 
              /* Move death note of SRC from P to INSN.  */
                }
 
              /* Move death note of SRC from P to INSN.  */
@@ -563,6 +407,7 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
                  if (REG_LIVE_LENGTH (dregno) >= 0)
                    REG_LIVE_LENGTH (dregno) += d_length;
                  REG_N_CALLS_CROSSED (dregno) += d_n_calls;
                  if (REG_LIVE_LENGTH (dregno) >= 0)
                    REG_LIVE_LENGTH (dregno) += d_length;
                  REG_N_CALLS_CROSSED (dregno) += d_n_calls;
+                 REG_FREQ_CALLS_CROSSED (dregno) += d_freq_calls;
                }
            }
 
                }
            }
 
@@ -599,15 +444,14 @@ optimize_reg_copy_2 (rtx insn, rtx dest, rtx src)
   rtx set;
   int sregno = REGNO (src);
   int dregno = REGNO (dest);
   rtx set;
   int sregno = REGNO (src);
   int dregno = REGNO (dest);
+  basic_block bb = BLOCK_FOR_INSN (insn);
 
   for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
     {
 
   for (p = NEXT_INSN (insn); p; p = NEXT_INSN (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).  */
-      if (perhaps_ends_bb_p (p))
-       break;
-      else if (! INSN_P (p))
+      if (! INSN_P (p))
        continue;
        continue;
+      if (BLOCK_FOR_INSN (p) != bb)
+       break;
 
       set = single_set (p);
       if (set && SET_SRC (set) == dest && SET_DEST (set) == src
 
       set = single_set (p);
       if (set && SET_SRC (set) == dest && SET_DEST (set) == src
@@ -621,12 +465,26 @@ optimize_reg_copy_2 (rtx insn, rtx dest, rtx src)
            if (INSN_P (q))
              {
                if (reg_mentioned_p (dest, PATTERN (q)))
            if (INSN_P (q))
              {
                if (reg_mentioned_p (dest, PATTERN (q)))
-                 PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
+                 {
+                   rtx note;
+
+                   PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
+                   note = FIND_REG_INC_NOTE (q, dest);
+                   if (note)
+                     {
+                       remove_note (q, note);
+                       add_reg_note (q, REG_INC, src);
+                     }
+                   df_insn_rescan (q);
+                 }
 
                if (CALL_P (q))
                  {
 
                if (CALL_P (q))
                  {
+                   int freq = REG_FREQ_FROM_BB  (BLOCK_FOR_INSN (q));
                    REG_N_CALLS_CROSSED (dregno)--;
                    REG_N_CALLS_CROSSED (sregno)++;
                    REG_N_CALLS_CROSSED (dregno)--;
                    REG_N_CALLS_CROSSED (sregno)++;
+                   REG_FREQ_CALLS_CROSSED (dregno) -= freq;
+                   REG_FREQ_CALLS_CROSSED (sregno) += freq;
                  }
              }
 
                  }
              }
 
@@ -656,8 +514,9 @@ 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 src_reg = XEXP (src, 0);
   int src_no = REGNO (src_reg);
   int dst_no = REGNO (dest);
-  rtx p, set;
+  rtx p, set, set_insn;
   enum machine_mode old_mode;
   enum machine_mode old_mode;
+  basic_block bb = BLOCK_FOR_INSN (insn);
 
   if (src_no < FIRST_PSEUDO_REGISTER
       || dst_no < FIRST_PSEUDO_REGISTER
 
   if (src_no < FIRST_PSEUDO_REGISTER
       || dst_no < FIRST_PSEUDO_REGISTER
@@ -665,13 +524,12 @@ optimize_reg_copy_3 (rtx insn, rtx dest, rtx src)
       || REG_N_DEATHS (src_no) != 1
       || REG_N_SETS (src_no) != 1)
     return;
       || 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))
   for (p = PREV_INSN (insn); p && ! reg_set_p (src_reg, p); p = PREV_INSN (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).  */
-    if (perhaps_ends_bb_p (p))
+    if (INSN_P (p) && BLOCK_FOR_INSN (p) != bb)
       break;
 
       break;
 
-  if (! p)
+  if (! p || BLOCK_FOR_INSN (p) != bb)
     return;
 
   if (! (set = single_set (p))
     return;
 
   if (! (set = single_set (p))
@@ -690,10 +548,10 @@ optimize_reg_copy_3 (rtx insn, rtx dest, rtx src)
   /* Do not use a SUBREG to truncate from one mode to another if truncation
      is not a nop.  */
   if (GET_MODE_BITSIZE (GET_MODE (src_reg)) <= GET_MODE_BITSIZE (GET_MODE (src))
   /* Do not use a SUBREG to truncate from one mode to another if truncation
      is not a nop.  */
   if (GET_MODE_BITSIZE (GET_MODE (src_reg)) <= GET_MODE_BITSIZE (GET_MODE (src))
-      && !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (src)),
-                                GET_MODE_BITSIZE (GET_MODE (src_reg))))
+      && !TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (src), GET_MODE (src_reg)))
     return;
 
     return;
 
+  set_insn = p;
   old_mode = GET_MODE (src_reg);
   PUT_MODE (src_reg, GET_MODE (src));
   XEXP (src, 0) = SET_SRC (set);
   old_mode = GET_MODE (src_reg);
   PUT_MODE (src_reg, GET_MODE (src));
   XEXP (src, 0) = SET_SRC (set);
@@ -726,9 +584,19 @@ optimize_reg_copy_3 (rtx insn, rtx dest, rtx src)
     }
   else
     {
     }
   else
     {
-      rtx note = find_reg_note (p, REG_EQUAL, NULL_RTX);
+      rtx note = find_reg_note (set_insn, REG_EQUAL, NULL_RTX);
       if (note)
       if (note)
-       remove_note (p, note);
+       {
+         if (rtx_equal_p (XEXP (note, 0), XEXP (src, 0)))
+           {
+             XEXP (note, 0)
+               = gen_rtx_fmt_e (GET_CODE (src), GET_MODE (src),
+                                XEXP (note, 0));
+             df_notes_rescan (set_insn);
+           }
+         else
+           remove_note (set_insn, note);
+       }
     }
 }
 
     }
 }
 
@@ -737,7 +605,7 @@ optimize_reg_copy_3 (rtx insn, rtx dest, rtx src)
    instead moving the value to dest directly before the operation.  */
 
 static void
    instead moving the value to dest directly before the operation.  */
 
 static void
-copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid)
+copy_src_to_dest (rtx insn, rtx src, rtx dest)
 {
   rtx seq;
   rtx link;
 {
   rtx seq;
   rtx link;
@@ -748,9 +616,6 @@ copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid)
   rtx *p_move_notes;
   int src_regno;
   int dest_regno;
   rtx *p_move_notes;
   int src_regno;
   int dest_regno;
-  int bb;
-  int insn_uid;
-  int move_uid;
 
   /* A REG_LIVE_LENGTH of -1 indicates the register is equivalent to a constant
      or memory location and is used infrequently; a REG_LIVE_LENGTH of -2 is
 
   /* A REG_LIVE_LENGTH of -1 indicates the register is equivalent to a constant
      or memory location and is used infrequently; a REG_LIVE_LENGTH of -2 is
@@ -806,42 +671,20 @@ copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid)
       *p_move_notes = NULL_RTX;
       *p_insn_notes = NULL_RTX;
 
       *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)
-           {
-             BB_HEAD (BASIC_BLOCK (bb)) = move_insn;
-             regmove_bb_head[insn_uid] = -1;
-           }
-       }
-
       /* Update the various register tables.  */
       dest_regno = REGNO (dest);
       /* Update the various register tables.  */
       dest_regno = REGNO (dest);
-      REG_N_SETS (dest_regno) ++;
+      INC_REG_N_SETS (dest_regno, 1);
       REG_LIVE_LENGTH (dest_regno)++;
       REG_LIVE_LENGTH (dest_regno)++;
-      if (REGNO_FIRST_UID (dest_regno) == insn_uid)
-       REGNO_FIRST_UID (dest_regno) = move_uid;
-
       src_regno = REGNO (src);
       if (! find_reg_note (move_insn, REG_DEAD, src))
        REG_LIVE_LENGTH (src_regno)++;
       src_regno = REGNO (src);
       if (! find_reg_note (move_insn, REG_DEAD, src))
        REG_LIVE_LENGTH (src_regno)++;
-
-      if (REGNO_FIRST_UID (src_regno) == insn_uid)
-       REGNO_FIRST_UID (src_regno) = move_uid;
-
-      if (REGNO_LAST_UID (src_regno) == insn_uid)
-       REGNO_LAST_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.  */
 
     }
 }
 
 /* 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;
+static basic_block *reg_set_in_bb;
 
 /* Size of reg_set_in_bb array.  */
 static unsigned int max_reg_computed;
 
 /* Size of reg_set_in_bb array.  */
 static unsigned int max_reg_computed;
@@ -854,8 +697,7 @@ static unsigned int max_reg_computed;
    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
    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 bool
 reg_is_remote_constant_p (rtx reg, rtx insn)
 
 static bool
 reg_is_remote_constant_p (rtx reg, rtx insn)
@@ -867,47 +709,30 @@ reg_is_remote_constant_p (rtx reg, rtx insn)
   if (!reg_set_in_bb)
     {
       max_reg_computed = max = max_reg_num ();
   if (!reg_set_in_bb)
     {
       max_reg_computed = max = max_reg_num ();
-      reg_set_in_bb = xcalloc (max, sizeof (*reg_set_in_bb));
+      reg_set_in_bb = XCNEWVEC (basic_block, max);
 
       FOR_EACH_BB (bb)
 
       FOR_EACH_BB (bb)
-       for (p = BB_HEAD (bb); p != NEXT_INSN (BB_END (bb));
-            p = NEXT_INSN (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;
-       }
+       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;
+         }
     }
     }
+
   gcc_assert (REGNO (reg) < max_reg_computed);
   if (reg_set_in_bb[REGNO (reg)] == NULL)
     return false;
   gcc_assert (REGNO (reg) < max_reg_computed);
   if (reg_set_in_bb[REGNO (reg)] == NULL)
     return false;
-  if (reg_set_in_bb[REGNO (reg)] != BLOCK_FOR_INSN (insn))
-    return true;
-  /* Look for the set.  */
-  for (p = BB_HEAD (BLOCK_FOR_INSN (insn)); p != insn; p = NEXT_INSN (p))
-    {
-      rtx s;
-
-      if (!INSN_P (p))
-       continue;
-      s = single_set (p);
-      if (s != 0
-         && REG_P (SET_DEST (s)) && REGNO (SET_DEST (s)) == REGNO (reg))
-       {
-         /* The register is set in the same basic block.  */
-         return false;
-       }
-    }
-  return true;
+  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
 }
 
 /* INSN is adding a CONST_INT to a REG.  We search backwards looking for
@@ -932,7 +757,8 @@ static int
 fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset)
 {
   rtx p, dst_death = 0;
 fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset)
 {
   rtx p, dst_death = 0;
-  int length, num_calls = 0;
+  int length, num_calls = 0, freq_calls = 0;
+  basic_block bb = BLOCK_FOR_INSN (insn);
 
   /* If SRC dies in INSN, we'd have to move the death note.  This is
      considered to be very unlikely, so we just skip the optimization
 
   /* If SRC dies in INSN, we'd have to move the death note.  This is
      considered to be very unlikely, so we just skip the optimization
@@ -946,23 +772,21 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset)
     {
       rtx pset;
 
     {
       rtx pset;
 
-      /* ??? 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;
-      else if (! INSN_P (p))
+      if (! INSN_P (p))
        continue;
        continue;
+      if (BLOCK_FOR_INSN (p) != bb)
+       break;
 
       if (find_regno_note (p, REG_DEAD, REGNO (dst)))
        dst_death = p;
 
       if (find_regno_note (p, REG_DEAD, REGNO (dst)))
        dst_death = p;
-      if (! dst_death)
+      if (! dst_death && !DEBUG_INSN_P (p))
        length++;
 
       pset = single_set (p);
       if (pset && SET_DEST (pset) == dst
          && GET_CODE (SET_SRC (pset)) == PLUS
          && XEXP (SET_SRC (pset), 0) == src
        length++;
 
       pset = single_set (p);
       if (pset && SET_DEST (pset) == dst
          && GET_CODE (SET_SRC (pset)) == PLUS
          && XEXP (SET_SRC (pset), 0) == src
-         && GET_CODE (XEXP (SET_SRC (pset), 1)) == CONST_INT)
+         && CONST_INT_P (XEXP (SET_SRC (pset), 1)))
        {
          HOST_WIDE_INT newconst
            = INTVAL (offset) - INTVAL (XEXP (SET_SRC (pset), 1));
        {
          HOST_WIDE_INT newconst
            = INTVAL (offset) - INTVAL (XEXP (SET_SRC (pset), 1));
@@ -976,6 +800,7 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset)
                  remove_death (REGNO (dst), dst_death);
                  REG_LIVE_LENGTH (REGNO (dst)) += length;
                  REG_N_CALLS_CROSSED (REGNO (dst)) += num_calls;
                  remove_death (REGNO (dst), dst_death);
                  REG_LIVE_LENGTH (REGNO (dst)) += length;
                  REG_N_CALLS_CROSSED (REGNO (dst)) += num_calls;
+                 REG_FREQ_CALLS_CROSSED (REGNO (dst)) += freq_calls;
                }
 
              if (dump_file)
                }
 
              if (dump_file)
@@ -986,11 +811,10 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset)
 #ifdef AUTO_INC_DEC
              for (p = PREV_INSN (insn); p; p = PREV_INSN (p))
                {
 #ifdef AUTO_INC_DEC
              for (p = PREV_INSN (insn); p; p = PREV_INSN (p))
                {
-                 if (LABEL_P (p)
-                     || JUMP_P (p))
-                   break;
                  if (! INSN_P (p))
                    continue;
                  if (! INSN_P (p))
                    continue;
+                 if (BLOCK_FOR_INSN (p) != bb)
+                   break;
                  if (reg_overlap_mentioned_p (dst, PATTERN (p)))
                    {
                      if (try_auto_increment (p, insn, 0, dst, newconst, 0))
                  if (reg_overlap_mentioned_p (dst, PATTERN (p)))
                    {
                      if (try_auto_increment (p, insn, 0, dst, newconst, 0))
@@ -1000,11 +824,10 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset)
                }
              for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
                {
                }
              for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
                {
-                 if (LABEL_P (p)
-                     || JUMP_P (p))
-                   break;
                  if (! INSN_P (p))
                    continue;
                  if (! INSN_P (p))
                    continue;
+                 if (BLOCK_FOR_INSN (p) != bb)
+                   break;
                  if (reg_overlap_mentioned_p (dst, PATTERN (p)))
                    {
                      try_auto_increment (p, insn, 0, dst, newconst, 1);
                  if (reg_overlap_mentioned_p (dst, PATTERN (p)))
                    {
                      try_auto_increment (p, insn, 0, dst, newconst, 1);
@@ -1028,12 +851,15 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset)
       if (CALL_P (p))
        {
          if (! dst_death)
       if (CALL_P (p))
        {
          if (! dst_death)
-           num_calls++;
+           {
+             num_calls++;
+             freq_calls += REG_FREQ_FROM_BB  (BLOCK_FOR_INSN (p));
+           }
 
          if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
            break;
 
 
          if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
            break;
 
-         if (call_used_regs [REGNO (dst)]
+         if ((HARD_REGISTER_P (dst) && call_used_regs [REGNO (dst)])
              || find_reg_fusage (p, CLOBBER, dst))
            break;
        }
              || find_reg_fusage (p, CLOBBER, dst))
            break;
        }
@@ -1044,70 +870,35 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset)
   return 0;
 }
 
   return 0;
 }
 
-/* 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).  */
+/* A forward pass.  Replace output operands with input operands.  */
 
 static void
 
 static void
-regmove_optimize (rtx f, int nregs)
+regmove_forward_pass (void)
 {
 {
-  int old_max_uid = get_max_uid ();
-  rtx insn;
-  struct match match;
-  int pass;
-  int i;
-  rtx copy_src, copy_dst;
   basic_block bb;
   basic_block bb;
+  rtx insn;
 
 
-  /* ??? Hack.  Regmove doesn't examine the CFG, and gets mightily
-     confused by non-call exceptions ending blocks.  */
-  if (flag_non_call_exceptions)
+  if (! flag_expensive_optimizations)
     return;
 
     return;
 
-  /* Find out where a potential flags register is live, and so that we
-     can suppress some optimizations in those zones.  */
-  mark_flags_life_zones (discover_flags_reg ());
-
-  regno_src_regno = XNEWVEC (int, nregs);
-  for (i = nregs; --i >= 0; ) regno_src_regno[i] = -1;
+  if (dump_file)
+    fprintf (dump_file, "Starting forward pass...\n");
 
 
-  regmove_bb_head = XNEWVEC (int, old_max_uid + 1);
-  for (i = old_max_uid; i >= 0; i--) regmove_bb_head[i] = -1;
   FOR_EACH_BB (bb)
   FOR_EACH_BB (bb)
-    regmove_bb_head[INSN_UID (BB_HEAD (bb))] = bb->index;
-
-  /* A forward/backward pass.  Replace output operands with input operands.  */
-
-  for (pass = 0; pass <= 2; pass++)
     {
     {
-      if (! flag_regmove && pass >= flag_expensive_optimizations)
-       goto done;
-
-      if (dump_file)
-       fprintf (dump_file, "Starting %s pass...\n",
-                pass ? "backward" : "forward");
-
-      for (insn = pass ? get_last_insn () : f; insn;
-          insn = pass ? PREV_INSN (insn) : NEXT_INSN (insn))
+      FOR_BB_INSNS (bb, insn)
        {
        {
-         rtx set;
-         int op_no, match_no;
-
-         set = single_set (insn);
+         rtx set = single_set (insn);
          if (! set)
            continue;
 
          if (! set)
            continue;
 
-         if (flag_expensive_optimizations && ! pass
-             && (GET_CODE (SET_SRC (set)) == SIGN_EXTEND
-                 || GET_CODE (SET_SRC (set)) == ZERO_EXTEND)
+         if ((GET_CODE (SET_SRC (set)) == SIGN_EXTEND
+              || GET_CODE (SET_SRC (set)) == ZERO_EXTEND)
              && REG_P (XEXP (SET_SRC (set), 0))
              && REG_P (SET_DEST (set)))
            optimize_reg_copy_3 (insn, SET_DEST (set), SET_SRC (set));
 
              && 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
-             && REG_P (SET_SRC (set))
+         if (REG_P (SET_SRC (set))
              && REG_P (SET_DEST (set)))
            {
              /* If this is a register-register copy where SRC is not dead,
              && REG_P (SET_DEST (set)))
            {
              /* If this is a register-register copy where SRC is not dead,
@@ -1130,116 +921,35 @@ regmove_optimize (rtx f, int nregs)
                    }
                }
            }
                    }
                }
            }
-         if (! flag_regmove)
-           continue;
-
-         if (! find_matches (insn, &match))
-           continue;
-
-         /* Now scan through the operands looking for a source operand
-            which is supposed to match the destination operand.
-            Then scan forward for an instruction which uses the dest
-            operand.
-            If it dies there, then replace the dest in both operands with
-            the source operand.  */
-
-         for (op_no = 0; op_no < recog_data.n_operands; op_no++)
-           {
-             rtx src, dst, src_subreg;
-             enum reg_class src_class, dst_class;
-
-             match_no = match.with[op_no];
-
-             /* Nothing to do if the two operands aren't supposed to match.  */
-             if (match_no < 0)
-               continue;
-
-             src = recog_data.operand[op_no];
-             dst = recog_data.operand[match_no];
-
-             if (!REG_P (src))
-               continue;
-
-             src_subreg = src;
-             if (GET_CODE (dst) == SUBREG
-                 && GET_MODE_SIZE (GET_MODE (dst))
-                    >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dst))))
-               {
-                 dst = SUBREG_REG (dst);
-                 src_subreg = lowpart_subreg (GET_MODE (dst),
-                                              src, GET_MODE (src));
-                 if (!src_subreg)
-                   continue;
-               }
-             if (!REG_P (dst)
-                 || REGNO (dst) < FIRST_PSEUDO_REGISTER)
-               continue;
-
-             if (REGNO (src) < FIRST_PSEUDO_REGISTER)
-               {
-                 if (match.commutative[op_no] < op_no)
-                   regno_src_regno[REGNO (dst)] = REGNO (src);
-                 continue;
-               }
-
-             if (REG_LIVE_LENGTH (REGNO (src)) < 0)
-               continue;
-
-             /* op_no/src must be a read-only operand, and
-                match_operand/dst must be a write-only operand.  */
-             if (match.use[op_no] != READ
-                 || match.use[match_no] != WRITE)
-               continue;
-
-             if (match.early_clobber[match_no]
-                 && count_occurrences (PATTERN (insn), src, 0) > 1)
-               continue;
-
-             /* Make sure match_operand is the destination.  */
-             if (recog_data.operand[match_no] != SET_DEST (set))
-               continue;
-
-             /* If the operands already match, then there is nothing to do.  */
-             if (operands_match_p (src, dst))
-               continue;
-
-             /* But in the commutative case, we might find a better match.  */
-             if (match.commutative[op_no] >= 0)
-               {
-                 rtx comm = recog_data.operand[match.commutative[op_no]];
-                 if (operands_match_p (comm, dst)
-                     && (replacement_quality (comm)
-                         >= replacement_quality (src)))
-                   continue;
-               }
-
-             src_class = reg_preferred_class (REGNO (src));
-             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))
-               break;
-           }
        }
     }
        }
     }
+}
 
 
-  /* A backward pass.  Replace input operands with output operands.  */
+/* A backward pass.  Replace input operands with output operands.  */
+
+static void
+regmove_backward_pass (void)
+{
+  basic_block bb;
+  rtx insn, prev;
 
   if (dump_file)
     fprintf (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))
+  FOR_EACH_BB_REVERSE (bb)
     {
     {
-      if (INSN_P (insn))
+      /* ??? Use the safe iterator because fixup_match_2 can remove
+            insns via try_auto_increment.  */
+      FOR_BB_INSNS_REVERSE_SAFE (bb, insn, prev)
        {
        {
+         struct match match;
+         rtx copy_src, copy_dst;
          int op_no, match_no;
          int success = 0;
 
          int op_no, match_no;
          int success = 0;
 
+         if (! INSN_P (insn))
+           continue;
+
          if (! find_matches (insn, &match))
            continue;
 
          if (! find_matches (insn, &match))
            continue;
 
@@ -1255,7 +965,7 @@ regmove_optimize (rtx f, int nregs)
            {
              rtx set, p, src, dst;
              rtx src_note, dst_note;
            {
              rtx set, p, src, dst;
              rtx src_note, dst_note;
-             int num_calls = 0;
+             int num_calls = 0, freq_calls = 0;
              enum reg_class src_class, dst_class;
              int length;
 
              enum reg_class src_class, dst_class;
              int length;
 
@@ -1317,7 +1027,7 @@ regmove_optimize (rtx f, int nregs)
              if (REGNO (src) < FIRST_PSEUDO_REGISTER)
                {
                  if (GET_CODE (SET_SRC (set)) == PLUS
              if (REGNO (src) < FIRST_PSEUDO_REGISTER)
                {
                  if (GET_CODE (SET_SRC (set)) == PLUS
-                     && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT
+                     && CONST_INT_P (XEXP (SET_SRC (set), 1))
                      && XEXP (SET_SRC (set), 0) == src
                      && fixup_match_2 (insn, dst, src,
                                        XEXP (SET_SRC (set), 1)))
                      && XEXP (SET_SRC (set), 0) == src
                      && fixup_match_2 (insn, dst, src,
                                        XEXP (SET_SRC (set), 1)))
@@ -1392,15 +1102,13 @@ regmove_optimize (rtx f, int nregs)
                {
                  rtx pset;
 
                {
                  rtx pset;
 
-                 /* ??? 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;
-                 else if (! INSN_P (p))
+                 if (! INSN_P (p))
                    continue;
                    continue;
+                 if (BLOCK_FOR_INSN (p) != bb)
+                   break;
 
 
-                 length++;
+                 if (!DEBUG_INSN_P (p))
+                   length++;
 
                  /* ??? See if all of SRC is set in P.  This test is much
                     more conservative than it needs to be.  */
 
                  /* ??? See if all of SRC is set in P.  This test is much
                     more conservative than it needs to be.  */
@@ -1408,35 +1116,41 @@ regmove_optimize (rtx f, int nregs)
                  if (pset && SET_DEST (pset) == src)
                    {
                      /* We use validate_replace_rtx, in case there
                  if (pset && SET_DEST (pset) == src)
                    {
                      /* We use validate_replace_rtx, in case there
-                        are multiple identical source operands.  All of
-                        them have to be changed at the same time.  */
+                        are multiple identical source operands.  All
+                        of them have to be changed at the same time:
+                        when validate_replace_rtx() calls
+                        apply_change_group().  */
+                     validate_change (p, &SET_DEST (pset), dst, 1);
                      if (validate_replace_rtx (src, dst, insn))
                      if (validate_replace_rtx (src, dst, insn))
-                       {
-                         if (validate_change (p, &SET_DEST (pset),
-                                              dst, 0))
-                           success = 1;
-                         else
-                           {
-                             /* Change all source operands back.
-                                This modifies the dst as a side-effect.  */
-                             validate_replace_rtx (dst, src, insn);
-                             /* Now make sure the dst is right.  */
-                             validate_change (insn,
-                                              recog_data.operand_loc[match_no],
-                                              dst, 0);
-                           }
-                       }
+                       success = 1;
                      break;
                    }
 
                      break;
                    }
 
-                 /* We can't make this change if SRC is read or
+                 /* We can't make this change if DST is mentioned at
+                    all in P, since we are going to change its value.
+                    We can't make this change if SRC is read or
                     partially written in P, since we are going to
                     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_mentioned_p (dst, PATTERN (p)))
-                   break;
+                    eliminate SRC.  However, if it's a debug insn, we
+                    can't refrain from making the change, for this
+                    would cause codegen differences, so instead we
+                    invalidate debug expressions that reference DST,
+                    and adjust references to SRC in them so that they
+                    become references to DST.  */
+                 if (reg_mentioned_p (dst, PATTERN (p)))
+                   {
+                     if (DEBUG_INSN_P (p))
+                       validate_change (p, &INSN_VAR_LOCATION_LOC (p),
+                                        gen_rtx_UNKNOWN_VAR_LOC (), 1);
+                     else
+                       break;
+                   }
+                 if (reg_overlap_mentioned_p (src, PATTERN (p)))
+                   {
+                     if (DEBUG_INSN_P (p))
+                       validate_replace_rtx_group (src, dst, p);
+                     else
+                       break;
+                   }
 
                  /* If we have passed a call instruction, and the
                     pseudo-reg DST is not already live across a call,
 
                  /* If we have passed a call instruction, and the
                     pseudo-reg DST is not already live across a call,
@@ -1444,6 +1158,7 @@ regmove_optimize (rtx f, int nregs)
                  if (CALL_P (p))
                    {
                      num_calls++;
                  if (CALL_P (p))
                    {
                      num_calls++;
+                     freq_calls += REG_FREQ_FROM_BB  (BLOCK_FOR_INSN (p));
 
                      if (REG_N_CALLS_CROSSED (REGNO (dst)) == 0)
                        break;
 
                      if (REG_N_CALLS_CROSSED (REGNO (dst)) == 0)
                        break;
@@ -1471,11 +1186,13 @@ regmove_optimize (rtx f, int nregs)
                  dstno = REGNO (dst);
                  srcno = REGNO (src);
 
                  dstno = REGNO (dst);
                  srcno = REGNO (src);
 
-                 REG_N_SETS (dstno)++;
-                 REG_N_SETS (srcno)--;
+                 INC_REG_N_SETS (dstno, 1);
+                 INC_REG_N_SETS (srcno, -1);
 
                  REG_N_CALLS_CROSSED (dstno) += num_calls;
                  REG_N_CALLS_CROSSED (srcno) -= num_calls;
 
                  REG_N_CALLS_CROSSED (dstno) += num_calls;
                  REG_N_CALLS_CROSSED (srcno) -= num_calls;
+                 REG_FREQ_CALLS_CROSSED (dstno) += freq_calls;
+                 REG_FREQ_CALLS_CROSSED (srcno) -= freq_calls;
 
                  REG_LIVE_LENGTH (dstno) += length;
                  if (REG_LIVE_LENGTH (srcno) >= 0)
 
                  REG_LIVE_LENGTH (dstno) += length;
                  if (REG_LIVE_LENGTH (srcno) >= 0)
@@ -1495,38 +1212,57 @@ regmove_optimize (rtx f, int nregs)
 
                  break;
                }
 
                  break;
                }
+             else if (num_changes_pending () > 0)
+               cancel_changes (0);
            }
 
          /* If we weren't able to replace any of the alternatives, try an
             alternative approach of copying the source to the destination.  */
          if (!success && copy_src != NULL_RTX)
            }
 
          /* If we weren't able to replace any of the alternatives, try an
             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_EACH_BB (bb)
-    {
-      rtx end = BB_END (bb);
-      rtx new = end;
-      rtx next = NEXT_INSN (new);
-      while (next != 0 && INSN_UID (next) >= old_max_uid
-            && (bb->next_bb == EXIT_BLOCK_PTR || BB_HEAD (bb->next_bb) != next))
-       new = next, next = NEXT_INSN (new);
-      BB_END (bb) = new;
-    }
+/* Main entry for the register move optimization.  */
+
+static unsigned int
+regmove_optimize (void)
+{
+  int i;
+  int nregs = max_reg_num ();
+
+  df_note_add_problem ();
+  df_analyze ();
+
+  regstat_init_n_sets_and_refs ();
+  regstat_compute_ri ();
+
+  if (flag_ira_loop_pressure)
+    ira_set_pseudo_classes (dump_file);
+
+  regno_src_regno = XNEWVEC (int, nregs);
+  for (i = nregs; --i >= 0; )
+    regno_src_regno[i] = -1;
+
+  /* A forward pass.  Replace output operands with input operands.  */
+  regmove_forward_pass ();
+
+  /* A backward pass.  Replace input operands with output operands.  */
+  regmove_backward_pass ();
 
 
- done:
   /* Clean up.  */
   free (regno_src_regno);
   /* 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;
     }
   if (reg_set_in_bb)
     {
       free (reg_set_in_bb);
       reg_set_in_bb = NULL;
     }
+  regstat_free_n_sets_and_refs ();
+  regstat_free_ri ();
+  if (flag_ira_loop_pressure)
+    free_reg_info ();
+  return 0;
 }
 
 /* Returns nonzero if INSN's pattern has matching constraints for any operand.
 }
 
 /* Returns nonzero if INSN's pattern has matching constraints for any operand.
@@ -1610,7 +1346,7 @@ find_matches (rtx insn, struct match *matchp)
          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':
          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_CONSTRAINT ((unsigned char) c, p) ))
+           if (targetm.class_likely_spilled_p (REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)))
              likely_spilled[op_no] = 1;
            break;
          }
              likely_spilled[op_no] = 1;
            break;
          }
@@ -1620,468 +1356,6 @@ find_matches (rtx insn, struct match *matchp)
   return any_matches;
 }
 
   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 (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 = 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_note)
-    {
-      /* Look for (set (regX) (op regA constX))
-                 (set (regY) (op regA constY))
-        and change that to
-                 (set (regA) (op regA constX)).
-                 (set (regY) (op regA constY-constX)).
-        This works for add and shift operations, if
-        regA is dead after or set by the second insn.  */
-
-      code = GET_CODE (SET_SRC (set));
-      if ((code == PLUS || code == LSHIFTRT
-          || code == ASHIFT || code == ASHIFTRT)
-         && XEXP (SET_SRC (set), 0) == src
-         && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
-       insn_const = INTVAL (XEXP (SET_SRC (set), 1));
-      else if (! stable_and_no_regs_but_for_p (SET_SRC (set), src, dst))
-       return 0;
-      else
-       /* We might find a src_note while scanning.  */
-       code = NOTE;
-    }
-
-  if (dump_file)
-    fprintf (dump_file,
-            "Could fix operand %d of insn %d matching operand %d.\n",
-            operand_number, INSN_UID (insn), match_number);
-
-  /* If SRC is equivalent to a constant set in a different basic block,
-     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))
-    return 0;
-
-  /* Scan forward to find the next instruction that
-     uses the output operand.  If the operand dies here,
-     then replace it in both instructions with
-     operand_number.  */
-
-  for (length = s_length = 0, p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
-    {
-      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).  */
-      if (perhaps_ends_bb_p (p))
-       break;
-      else if (! INSN_P (p))
-       continue;
-
-      length++;
-      if (src_note)
-       s_length++;
-
-      if (reg_set_p (src, p) || reg_set_p (dst, p)
-         || (GET_CODE (PATTERN (p)) == USE
-             && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
-       break;
-
-      /* See if all of DST dies in P.  This test is
-        slightly more conservative than it needs to be.  */
-      if ((dst_note = find_regno_note (p, REG_DEAD, REGNO (dst)))
-         && (GET_MODE (XEXP (dst_note, 0)) == GET_MODE (dst)))
-       {
-         /* If we would be moving INSN, check that we won't move it
-            into the shadow of a live a live flags register.  */
-         /* ??? We only try to move it in front of P, although
-                we could move it anywhere between OVERLAP and P.  */
-         if (overlap && GET_MODE (PREV_INSN (p)) != VOIDmode)
-           break;
-
-         if (! src_note)
-           {
-             rtx q;
-             rtx set2 = NULL_RTX;
-
-             /* If an optimization is done, the value of SRC while P
-                is executed will be changed.  Check that this is OK.  */
-             if (reg_overlap_mentioned_p (src, PATTERN (p)))
-               break;
-             for (q = p; q; q = NEXT_INSN (q))
-               {
-                 /* ??? 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 (q))
-                   {
-                     q = 0;
-                     break;
-                   }
-                 else if (! INSN_P (q))
-                   continue;
-                 else if (reg_overlap_mentioned_p (src, PATTERN (q))
-                          || reg_set_p (src, q))
-                   break;
-               }
-             if (q)
-               set2 = single_set (q);
-             if (! q || ! set2 || GET_CODE (SET_SRC (set2)) != code
-                 || XEXP (SET_SRC (set2), 0) != src
-                 || GET_CODE (XEXP (SET_SRC (set2), 1)) != CONST_INT
-                 || (SET_DEST (set2) != src
-                     && ! find_reg_note (q, REG_DEAD, src)))
-               {
-                 /* If this is a PLUS, we can still save a register by doing
-                    src += insn_const;
-                    P;
-                    src -= insn_const; .
-                    This also gives opportunities for subsequent
-                    optimizations in the backward pass, so do it there.  */
-                 if (code == PLUS && backward
-                     /* Don't do this if we can likely tie DST to SET_DEST
-                        of P later; we can't do this tying here if we got a
-                        hard register.  */
-                     && ! (dst_note && ! REG_N_CALLS_CROSSED (REGNO (dst))
-                           && single_set (p)
-                           && 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
-                        are not in the shadow of a live flags register.  */
-                     && GET_MODE (p) == VOIDmode)
-                   {
-                     search_end = q;
-                     q = insn;
-                     set2 = set;
-                     newconst = -insn_const;
-                     code = MINUS;
-                   }
-                 else
-                   break;
-               }
-             else
-               {
-                 newconst = INTVAL (XEXP (SET_SRC (set2), 1)) - insn_const;
-                 /* Reject out of range shifts.  */
-                 if (code != PLUS
-                     && (newconst < 0
-                         || ((unsigned HOST_WIDE_INT) newconst
-                             >= (GET_MODE_BITSIZE (GET_MODE
-                                                   (SET_SRC (set2)))))))
-                   break;
-                 if (code == PLUS)
-                   {
-                     post_inc = q;
-                     if (SET_DEST (set2) != src)
-                       post_inc_set = set2;
-                   }
-               }
-             /* We use 1 as last argument to validate_change so that all
-                changes are accepted or rejected together by apply_change_group
-                when it is called by validate_replace_rtx .  */
-             validate_change (q, &XEXP (SET_SRC (set2), 1),
-                              GEN_INT (newconst), 1);
-           }
-         validate_change (insn, recog_data.operand_loc[match_number], src, 1);
-         if (validate_replace_rtx (dst, src_subreg, p))
-           success = 1;
-         break;
-       }
-
-      if (reg_overlap_mentioned_p (dst, PATTERN (p)))
-       break;
-      if (! src_note && reg_overlap_mentioned_p (src, PATTERN (p)))
-       {
-         /* INSN was already checked to be movable wrt. the registers that it
-            sets / uses when we found no REG_DEAD note for src on it, but it
-            still might clobber the flags register.  We'll have to check that
-            we won't insert it into the shadow of a live flags register when
-            we finally know where we are to move it.  */
-         overlap = p;
-         src_note = find_reg_note (p, REG_DEAD, src);
-       }
-
-      /* 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 (CALL_P (p))
-       {
-         if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
-           break;
-
-         num_calls++;
-
-         if (src_note)
-           s_num_calls++;
-
-       }
-    }
-
-  if (! success)
-    return 0;
-
-  /* Remove the death note for DST from P.  */
-  remove_note (p, dst_note);
-  if (code == MINUS)
-    {
-      post_inc = emit_insn_after (copy_rtx (PATTERN (insn)), p);
-      if ((HAVE_PRE_INCREMENT || HAVE_PRE_DECREMENT)
-         && search_end
-         && try_auto_increment (search_end, post_inc, 0, src, newconst, 1))
-       post_inc = 0;
-      validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (insn_const), 0);
-      REG_N_SETS (REGNO (src))++;
-      REG_LIVE_LENGTH (REGNO (src))++;
-    }
-  if (overlap)
-    {
-      /* The lifetime of src and dest overlap,
-        but we can change this by moving insn.  */
-      rtx pat = PATTERN (insn);
-      if (src_note)
-       remove_note (overlap, src_note);
-      if ((HAVE_POST_INCREMENT || HAVE_POST_DECREMENT)
-         && code == PLUS
-         && try_auto_increment (overlap, insn, 0, src, insn_const, 0))
-       insn = overlap;
-      else
-       {
-         rtx notes = REG_NOTES (insn);
-
-         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;
-     if so, replace the instruction that set src
-     in the first place.  */
-
-  if (! overlap && (code == PLUS || code == MINUS))
-    {
-      rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-      rtx q, set2 = NULL_RTX;
-      int num_calls2 = 0, s_length2 = 0;
-
-      if (note && CONSTANT_P (XEXP (note, 0)))
-       {
-         for (q = PREV_INSN (insn); q; q = PREV_INSN (q))
-           {
-             /* ??? 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 (q))
-               {
-                 q = 0;
-                 break;
-               }
-             else if (! INSN_P (q))
-               continue;
-
-             s_length2++;
-             if (reg_set_p (src, q))
-               {
-                 set2 = single_set (q);
-                 break;
-               }
-             if (reg_overlap_mentioned_p (src, PATTERN (q)))
-               {
-                 q = 0;
-                 break;
-               }
-             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))
-           {
-             delete_insn (q);
-             REG_N_SETS (REGNO (src))--;
-             REG_N_CALLS_CROSSED (REGNO (src)) -= num_calls2;
-             REG_LIVE_LENGTH (REGNO (src)) -= s_length2;
-             insn_const = 0;
-           }
-       }
-    }
-
-  if ((HAVE_PRE_INCREMENT || HAVE_PRE_DECREMENT)
-          && (code == PLUS || code == MINUS) && insn_const
-          && try_auto_increment (p, insn, 0, src, insn_const, 1))
-    insn = p;
-  else if ((HAVE_POST_INCREMENT || HAVE_POST_DECREMENT)
-          && post_inc
-          && try_auto_increment (p, post_inc, post_inc_set, src, newconst, 0))
-    post_inc = 0;
-  /* If post_inc still prevails, try to find an
-     insn where it can be used as a pre-in/decrement.
-     If code is MINUS, this was already tried.  */
-  if (post_inc && code == PLUS
-  /* Check that newconst is likely to be usable
-     in a pre-in/decrement before starting the search.  */
-      && ((HAVE_PRE_INCREMENT && newconst > 0 && newconst <= MOVE_MAX)
-         || (HAVE_PRE_DECREMENT && newconst < 0 && newconst >= -MOVE_MAX))
-      && exact_log2 (newconst))
-    {
-      rtx q, inc_dest;
-
-      inc_dest = post_inc_set ? SET_DEST (post_inc_set) : src;
-      for (q = post_inc; (q = NEXT_INSN (q)); )
-       {
-         /* ??? 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 (q))
-           break;
-         else if (! INSN_P (q))
-           continue;
-         else if (src != inc_dest
-                  && (reg_overlap_mentioned_p (src, PATTERN (q))
-                      || reg_set_p (src, q)))
-           break;
-         else if (reg_set_p (inc_dest, q))
-           break;
-         else if (reg_overlap_mentioned_p (inc_dest, PATTERN (q)))
-           {
-             try_auto_increment (q, post_inc,
-                                 post_inc_set, inc_dest, newconst, 1);
-             break;
-           }
-       }
-    }
-
-  /* Move the death note for DST to INSN if it is used
-     there.  */
-  if (reg_overlap_mentioned_p (dst, PATTERN (insn)))
-    {
-      XEXP (dst_note, 1) = REG_NOTES (insn);
-      REG_NOTES (insn) = dst_note;
-    }
-
-  if (src_note)
-    {
-      /* Move the death note for SRC from INSN to P.  */
-      if (! overlap)
-       remove_note (insn, src_note);
-      XEXP (src_note, 1) = REG_NOTES (p);
-      REG_NOTES (p) = src_note;
-
-      REG_N_CALLS_CROSSED (REGNO (src)) += s_num_calls;
-    }
-
-  REG_N_SETS (REGNO (src))++;
-  REG_N_SETS (REGNO (dst))--;
-
-  REG_N_CALLS_CROSSED (REGNO (dst)) -= num_calls;
-
-  REG_LIVE_LENGTH (REGNO (src)) += s_length;
-  if (REG_LIVE_LENGTH (REGNO (dst)) >= 0)
-    {
-      REG_LIVE_LENGTH (REGNO (dst)) -= length;
-      /* REG_LIVE_LENGTH is only an approximation after
-        combine if sched is not run, so make sure that we
-        still have a reasonable value.  */
-      if (REG_LIVE_LENGTH (REGNO (dst)) < 2)
-       REG_LIVE_LENGTH (REGNO (dst)) = 2;
-    }
-  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 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.  */
-static int
-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 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);
-       for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-         if (fmt[i] == 'e'
-             && ! stable_and_no_regs_but_for_p (XEXP (x, i), src, dst))
-             return 0;
-       return 1;
-      }
-    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
-        the address of an unchanging MEM.  */
-      if (code == MEM
-         && ! stable_and_no_regs_but_for_p (XEXP (x, 0), src, dst))
-       return 0;
-      /* Fall through.  */
-    default:
-      return ! rtx_unstable_p (x);
-    }
-}
 \f
 
 static bool
 \f
 
 static bool
@@ -2090,21 +1364,14 @@ gate_handle_regmove (void)
   return (optimize > 0 && flag_regmove);
 }
 
   return (optimize > 0 && flag_regmove);
 }
 
-/* Register allocation pre-pass, to reduce number of moves necessary
-   for two-address machines.  */
-static unsigned int
-rest_of_handle_regmove (void)
-{
-  regmove_optimize (get_insns (), max_reg_num ());
-  cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
-  return 0;
-}
 
 
-struct tree_opt_pass pass_regmove =
+struct rtl_opt_pass pass_regmove =
 {
 {
+ {
+  RTL_PASS,
   "regmove",                            /* name */
   gate_handle_regmove,                  /* gate */
   "regmove",                            /* name */
   gate_handle_regmove,                  /* gate */
-  rest_of_handle_regmove,               /* execute */
+  regmove_optimize,                    /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
@@ -2113,8 +1380,7 @@ struct tree_opt_pass pass_regmove =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_dump_func |
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  'N'                                   /* letter */
+  TODO_df_finish | TODO_verify_rtl_sharing |
+  TODO_ggc_collect                      /* todo_flags_finish */
+ }
 };
 };
-