OSDN Git Service

* gcc.c-torture/execute/ieee/ieee.exp: Change sh-*-* to sh*-*-*.
[pf3gnuchains/gcc-fork.git] / gcc / loop.c
index f2d44cb..c81a2c6 100644 (file)
@@ -2,22 +2,22 @@
    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
    1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 /* This is the loop optimization pass of the compiler.
    It finds invariant computations within loops and moves them
@@ -52,6 +52,7 @@ Boston, MA 02111-1307, USA.  */
 #include "cselib.h"
 #include "except.h"
 #include "toplev.h"
+#include "predict.h"
 
 #define LOOP_REG_LIFETIME(LOOP, REGNO) \
 ((REGNO_LAST_LUID (REGNO) - REGNO_FIRST_LUID (REGNO)))
@@ -165,6 +166,7 @@ static void ignore_some_movables PARAMS ((struct loop_movables *));
 static void force_movables PARAMS ((struct loop_movables *));
 static void combine_movables PARAMS ((struct loop_movables *,
                                      struct loop_regs *));
+static int num_unmoved_movables PARAMS ((const struct loop *));
 static int regs_match_p PARAMS ((rtx, rtx, struct loop_movables *));
 static int rtx_equal_for_loop_p PARAMS ((rtx, rtx, struct loop_movables *,
                                         struct loop_regs *));
@@ -189,7 +191,7 @@ static void loop_givs_reduce PARAMS((struct loop *, struct iv_class *));
 static void loop_givs_rescan PARAMS((struct loop *, struct iv_class *,
                                     rtx *));
 static void loop_ivs_free PARAMS((struct loop *));
-static void strength_reduce PARAMS ((struct loop *, int, int));
+static void strength_reduce PARAMS ((struct loop *, int));
 static void find_single_use_in_loop PARAMS ((struct loop_regs *, rtx, rtx));
 static int valid_initial_value_p PARAMS ((rtx, rtx, int, rtx));
 static void find_mem_givs PARAMS ((const struct loop *, rtx, rtx, int, int));
@@ -232,7 +234,8 @@ static int last_use_this_basic_block PARAMS ((rtx, rtx));
 static void record_initial PARAMS ((rtx, rtx, void *));
 static void update_reg_last_use PARAMS ((rtx, rtx));
 static rtx next_insn_in_loop PARAMS ((const struct loop *, rtx));
-static void loop_regs_scan PARAMS ((const struct loop*, int, int *));
+static void loop_regs_scan PARAMS ((const struct loop *, int));
+static int count_insns_in_loop PARAMS ((const struct loop *));
 static void load_mems PARAMS ((const struct loop *));
 static int insert_loop_mem PARAMS ((rtx *, void *));
 static int replace_loop_mem PARAMS ((rtx *, void *));
@@ -250,7 +253,7 @@ static rtx gen_add_mult PARAMS ((rtx, rtx, rtx, rtx));
 static void loop_regs_update PARAMS ((const struct loop *, rtx));
 static int iv_add_mult_cost PARAMS ((rtx, rtx, rtx, rtx));
 
-static rtx loop_insn_emit_after PARAMS((const struct loop *, basic_block, 
+static rtx loop_insn_emit_after PARAMS((const struct loop *, basic_block,
                                        rtx, rtx));
 static rtx loop_call_insn_emit_before PARAMS((const struct loop *,
                                              basic_block, rtx, rtx));
@@ -258,6 +261,7 @@ static rtx loop_call_insn_hoist PARAMS((const struct loop *, rtx));
 static rtx loop_insn_sink_or_swim PARAMS((const struct loop *, rtx));
 
 static void loop_dump_aux PARAMS ((const struct loop *, FILE *, int));
+static void loop_delete_insns PARAMS ((rtx, rtx));
 void debug_ivs PARAMS ((const struct loop *));
 void debug_iv_class PARAMS ((const struct iv_class *));
 void debug_biv PARAMS ((const struct induction *));
@@ -279,8 +283,8 @@ typedef struct loop_replace_args
 } loop_replace_args;
 
 /* Nonzero iff INSN is between START and END, inclusive.  */
-#define INSN_IN_RANGE_P(INSN, START, END)      \
-  (INSN_UID (INSN) < max_uid_for_loop          \
+#define INSN_IN_RANGE_P(INSN, START, END)      \
+  (INSN_UID (INSN) < max_uid_for_loop          \
    && INSN_LUID (INSN) >= INSN_LUID (START)    \
    && INSN_LUID (INSN) <= INSN_LUID (END))
 
@@ -352,8 +356,8 @@ loop_optimize (f, dumpfile, flags)
      FILE *dumpfile;
      int flags;
 {
-  register rtx insn;
-  register int i;
+  rtx insn;
+  int i;
   struct loops loops_data;
   struct loops *loops = &loops_data;
   struct loop_info *loops_info;
@@ -518,7 +522,7 @@ scan_loop (loop, flags)
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
-  register int i;
+  int i;
   rtx loop_start = loop->start;
   rtx loop_end = loop->end;
   rtx p;
@@ -549,7 +553,6 @@ scan_loop (loop, flags)
 
   movables->head = 0;
   movables->last = 0;
-  movables->num = 0;
 
   /* Determine whether this loop starts with a jump down to a test at
      the end.  This will occur for a small number of loops with a test
@@ -636,7 +639,8 @@ scan_loop (loop, flags)
   /* Allocate extra space for REGs that might be created by load_mems.
      We allocate a little extra slop as well, in the hopes that we
      won't have to reallocate the regs array.  */
-  loop_regs_scan (loop, loop_info->mems_idx + 16, &insn_count);
+  loop_regs_scan (loop, loop_info->mems_idx + 16);
+  insn_count = count_insns_in_loop (loop);
 
   if (loop_dump_stream)
     {
@@ -701,6 +705,18 @@ scan_loop (loop, flags)
                }
            }
 
+         /* For parallels, add any possible uses to the depencies, as we can't move
+            the insn without resolving them first.  */
+         if (GET_CODE (PATTERN (p)) == PARALLEL)
+           {
+             for (i = 0; i < XVECLEN (PATTERN (p), 0); i++)
+               {
+                 rtx x = XVECEXP (PATTERN (p), 0, i);
+                 if (GET_CODE (x) == USE)
+                   dependencies = gen_rtx_EXPR_LIST (VOIDmode, XEXP (x, 0), dependencies);
+               }
+           }
+
          /* Don't try to optimize a register that was made
             by loop-optimization for an inner loop.
             We don't know its life-span, so we can't compute the benefit.  */
@@ -711,7 +727,7 @@ scan_loop (loop, flags)
                      something after this point in the loop might
                      depend on its value before the set).  */
                   ! reg_in_basic_block_p (p, SET_DEST (set))
-                  /* And the set is not guaranteed to be executed one
+                  /* And the set is not guaranteed to be executed once
                      the loop starts, or the value before the set is
                      needed before the set occurs...
 
@@ -745,8 +761,8 @@ scan_loop (loop, flags)
                   && ! ((maybe_never || call_passed)
                         && may_trap_p (src)))
            {
-             register struct movable *m;
-             register int regno = REGNO (SET_DEST (set));
+             struct movable *m;
+             int regno = REGNO (SET_DEST (set));
 
              /* A potential lossage is where we have a case where two insns
                 can be combined as long as they are both in the loop, but
@@ -769,6 +785,7 @@ scan_loop (loop, flags)
                  && (REGNO_LAST_UID (regno)
                      == INSN_UID (regs->array[regno].single_usage))
                  && regs->array[regno].set_in_loop == 1
+                 && GET_CODE (SET_SRC (set)) != ASM_OPERANDS
                  && ! side_effects_p (SET_SRC (set))
                  && ! find_reg_note (p, REG_RETVAL, NULL_RTX)
                  && (! SMALL_REGISTER_CLASSES
@@ -790,9 +807,7 @@ scan_loop (loop, flags)
                    = replace_rtx (REG_NOTES (regs->array[regno].single_usage),
                                   SET_DEST (set), copy_rtx (SET_SRC (set)));
 
-                 PUT_CODE (p, NOTE);
-                 NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED;
-                 NOTE_SOURCE_FILE (p) = 0;
+                 delete_insn (p);
                  regs->array[regno].set_in_loop = 0;
                  continue;
                }
@@ -877,10 +892,10 @@ scan_loop (loop, flags)
                       == SET_DEST (set))
                   && !reg_mentioned_p (SET_DEST (set), SET_SRC (set1)))
            {
-             register int regno = REGNO (SET_DEST (set));
+             int regno = REGNO (SET_DEST (set));
              if (regs->array[regno].set_in_loop == 2)
                {
-                 register struct movable *m;
+                 struct movable *m;
                  m = (struct movable *) xmalloc (sizeof (struct movable));
                  m->next = 0;
                  m->insn = p;
@@ -933,7 +948,7 @@ scan_loop (loop, flags)
       /* Past a call insn, we get to insns which might not be executed
         because the call might exit.  This matters for insns that trap.
         Constant and pure call insns always return, so they don't count.  */
-      else if (GET_CODE (p) == CALL_INSN && ! CONST_CALL_P (p))
+      else if (GET_CODE (p) == CALL_INSN && ! CONST_OR_PURE_CALL_P (p))
        call_passed = 1;
       /* Past a label or a jump, we get to insns for which we
         can't count on whether or how many times they will be
@@ -946,7 +961,7 @@ scan_loop (loop, flags)
                  beginning, don't set maybe_never for that.  This must be an
                  unconditional jump, otherwise the code at the top of the
                  loop might never be executed.  Unconditional jumps are
-                 followed a by barrier then loop end.  */
+                 followed by a barrier then the loop_end.  */
                && ! (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == loop->top
                     && NEXT_INSN (NEXT_INSN (p)) == loop_end
                     && any_uncondjump_p (p)))
@@ -1005,7 +1020,7 @@ scan_loop (loop, flags)
 
   /* Recalculate regs->array if load_mems has created new registers.  */
   if (max_reg_num () > regs->num)
-    loop_regs_scan (loop, 0, &insn_count);
+    loop_regs_scan (loop, 0);
 
   for (update_start = loop_start;
        PREV_INSN (update_start)
@@ -1023,14 +1038,14 @@ scan_loop (loop, flags)
        /* Ensure our label doesn't go away.  */
        LABEL_NUSES (update_end)++;
 
-      strength_reduce (loop, insn_count, flags);
+      strength_reduce (loop, flags);
 
       reg_scan_update (update_start, update_end, loop_max_reg);
       loop_max_reg = max_reg_num ();
 
       if (update_end && GET_CODE (update_end) == CODE_LABEL
          && --LABEL_NUSES (update_end) == 0)
-       delete_insn (update_end);
+       delete_related_insns (update_end);
     }
 
 
@@ -1237,7 +1252,7 @@ static void
 ignore_some_movables (movables)
      struct loop_movables *movables;
 {
-  register struct movable *m, *m1;
+  struct movable *m, *m1;
 
   for (m = movables->head; m; m = m->next)
     {
@@ -1269,7 +1284,8 @@ static void
 force_movables (movables)
      struct loop_movables *movables;
 {
-  register struct movable *m, *m1;
+  struct movable *m, *m1;
+
   for (m1 = movables->head; m1; m1 = m1->next)
     /* Omit this if moving just the (SET (REG) 0) of a zero-extend.  */
     if (!m1->partial && !m1->done)
@@ -1309,7 +1325,7 @@ combine_movables (movables, regs)
      struct loop_movables *movables;
      struct loop_regs *regs;
 {
-  register struct movable *m;
+  struct movable *m;
   char *matched_regs = (char *) xmalloc (regs->num);
   enum machine_mode mode;
 
@@ -1321,7 +1337,7 @@ combine_movables (movables, regs)
     if (m->match == 0 && regs->array[m->regno].n_times_set == 1
        && !m->partial)
       {
-       register struct movable *m1;
+       struct movable *m1;
        int regno = m->regno;
 
        memset (matched_regs, 0, regs->num);
@@ -1330,7 +1346,7 @@ combine_movables (movables, regs)
        /* We want later insns to match the first one.  Don't make the first
           one match any later ones.  So start this loop at m->next.  */
        for (m1 = m->next; m1; m1 = m1->next)
-         if (m != m1 && m1->match == 0 
+         if (m != m1 && m1->match == 0
              && regs->array[m1->regno].n_times_set == 1
              /* A reg used outside the loop mustn't be eliminated.  */
              && !m1->global
@@ -1374,7 +1390,7 @@ combine_movables (movables, regs)
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
-      register struct movable *m0 = 0;
+      struct movable *m0 = 0;
 
       /* Combine all the registers for extension from mode MODE.
         Don't combine any that are used outside this loop.  */
@@ -1382,7 +1398,8 @@ combine_movables (movables, regs)
        if (m->partial && ! m->global
            && mode == GET_MODE (SET_SRC (PATTERN (NEXT_INSN (m->insn)))))
          {
-           register struct movable *m1;
+           struct movable *m1;
+
            int first = REGNO_FIRST_LUID (m->regno);
            int last = REGNO_LAST_LUID (m->regno);
 
@@ -1420,6 +1437,24 @@ combine_movables (movables, regs)
   /* Clean up.  */
   free (matched_regs);
 }
+
+/* Returns the number of movable instructions in LOOP that were not
+   moved outside the loop.  */
+
+static int
+num_unmoved_movables (loop)
+     const struct loop *loop;
+{
+  int num = 0;
+  struct movable *m;
+
+  for (m = LOOP_MOVABLES (loop)->head; m; m = m->next)
+    if (!m->done)
+      ++num;
+
+  return num;
+}
+
 \f
 /* Return 1 if regs X and Y will become the same if moved.  */
 
@@ -1458,11 +1493,11 @@ rtx_equal_for_loop_p (x, y, movables, regs)
      struct loop_movables *movables;
      struct loop_regs *regs;
 {
-  register int i;
-  register int j;
-  register struct movable *m;
-  register enum rtx_code code;
-  register const char *fmt;
+  int i;
+  int j;
+  struct movable *m;
+  enum rtx_code code;
+  const char *fmt;
 
   if (x == y)
     return 1;
@@ -1569,7 +1604,7 @@ rtx_equal_for_loop_p (x, y, movables, regs)
 \f
 /* If X contains any LABEL_REF's, add REG_LABEL notes for them to all
    insns in INSNS which use the reference.  LABEL_NUSES for CODE_LABEL
-   references is incremented once for each added note. */
+   references is incremented once for each added note.  */
 
 static void
 add_label_notes (x, insns)
@@ -1591,7 +1626,7 @@ add_label_notes (x, insns)
       for (insn = insns; insn; insn = NEXT_INSN (insn))
        if (reg_mentioned_p (XEXP (x, 0), insn))
          {
-           REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL, XEXP (x, 0),
+           REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0),
                                                  REG_NOTES (insn));
            if (LABEL_P (XEXP (x, 0)))
              LABEL_NUSES (XEXP (x, 0))++;
@@ -1623,8 +1658,8 @@ move_movables (loop, movables, threshold, insn_count)
   struct loop_regs *regs = LOOP_REGS (loop);
   int nregs = regs->num;
   rtx new_start = 0;
-  register struct movable *m;
-  register rtx p;
+  struct movable *m;
+  rtx p;
   rtx loop_start = loop->start;
   rtx loop_end = loop->end;
   /* Map of pseudo-register replacements to handle combining
@@ -1633,8 +1668,6 @@ move_movables (loop, movables, threshold, insn_count)
   rtx *reg_map = (rtx *) xcalloc (nregs, sizeof (rtx));
   char *already_moved = (char *) xcalloc (nregs, sizeof (char));
 
-  movables->num = 0;
-
   for (m = movables->head; m; m = m->next)
     {
       /* Describe this movable insn.  */
@@ -1663,9 +1696,6 @@ move_movables (loop, movables, threshold, insn_count)
                     INSN_UID (m->forces->insn));
        }
 
-      /* Count movables.  Value used in heuristics in strength_reduce.  */
-      movables->num++;
-
       /* Ignore the insn if it's already done (it matched something else).
         Otherwise, see if it is now safe to move.  */
 
@@ -1680,8 +1710,8 @@ move_movables (loop, movables, threshold, insn_count)
                                                       m->insn))))
          && (! m->forces || m->forces->done))
        {
-         register int regno;
-         register rtx p;
+         int regno;
+         rtx p;
          int savings = m->savings;
 
          /* We have an insn that is safe to move.
@@ -1717,7 +1747,7 @@ move_movables (loop, movables, threshold, insn_count)
                  && regs->array[m->forces->regno].n_times_set == 1))
            {
              int count;
-             register struct movable *m1;
+             struct movable *m1;
              rtx first = NULL_RTX;
 
              /* Now move the insns that set the reg.  */
@@ -1906,6 +1936,7 @@ move_movables (loop, movables, threshold, insn_count)
                              if (temp == fn_address_insn)
                                fn_address_insn = i1;
                              REG_NOTES (i1) = REG_NOTES (temp);
+                             REG_NOTES (temp) = NULL;
                              delete_insn (temp);
                            }
                          if (new_start == 0)
@@ -1921,8 +1952,8 @@ move_movables (loop, movables, threshold, insn_count)
                          rtx tem;
 
                          start_sequence ();
-                         tem = expand_binop
-                           (GET_MODE (reg), and_optab, reg,
+                         tem = expand_simple_binop
+                           (GET_MODE (reg), AND, reg,
                             GEN_INT ((((HOST_WIDE_INT) 1
                                        << GET_MODE_BITSIZE (m->savemode)))
                                      - 1),
@@ -1971,6 +2002,7 @@ move_movables (loop, movables, threshold, insn_count)
                      if (REG_NOTES (i1) == 0)
                        {
                          REG_NOTES (i1) = REG_NOTES (p);
+                         REG_NOTES (p) = NULL;
 
                          /* If there is a REG_EQUAL note present whose value
                             is not loop invariant, then delete it, since it
@@ -2073,16 +2105,12 @@ move_movables (loop, movables, threshold, insn_count)
                         and prevent further processing of it.  */
                      m1->done = 1;
 
-                     /* if library call, delete all insn except last, which
-                        is deleted below */
+                     /* if library call, delete all insns.  */
                      if ((temp = find_reg_note (m1->insn, REG_RETVAL,
                                                 NULL_RTX)))
-                       {
-                         for (temp = XEXP (temp, 0); temp != m1->insn;
-                              temp = NEXT_INSN (temp))
-                           delete_insn (temp);
-                       }
-                     delete_insn (m1->insn);
+                       delete_insn_chain (XEXP (temp, 0), m1->insn);
+                     else
+                       delete_insn (m1->insn);
 
                      /* Any other movable that loads the same register
                         MUST be moved.  */
@@ -2149,7 +2177,7 @@ loop_movables_free (movables)
       m_next = m->next;
       free (m);
     }
-}  
+}
 \f
 #if 0
 /* Scan X and replace the address of any MEM in it with ADDR.
@@ -2159,9 +2187,9 @@ static void
 replace_call_address (x, reg, addr)
      rtx x, reg, addr;
 {
-  register enum rtx_code code;
-  register int i;
-  register const char *fmt;
+  enum rtx_code code;
+  int i;
+  const char *fmt;
 
   if (x == 0)
     return;
@@ -2207,7 +2235,7 @@ replace_call_address (x, reg, addr)
        replace_call_address (XEXP (x, i), reg, addr);
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            replace_call_address (XVECEXP (x, i, j), reg, addr);
        }
@@ -2223,9 +2251,9 @@ count_nonfixed_reads (loop, x)
      const struct loop *loop;
      rtx x;
 {
-  register enum rtx_code code;
-  register int i;
-  register const char *fmt;
+  enum rtx_code code;
+  int i;
+  const char *fmt;
   int value;
 
   if (x == 0)
@@ -2260,7 +2288,7 @@ count_nonfixed_reads (loop, x)
        value += count_nonfixed_reads (loop, XEXP (x, i));
       if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            value += count_nonfixed_reads (loop, XVECEXP (x, i, j));
        }
@@ -2278,7 +2306,7 @@ static void
 prescan_loop (loop)
      struct loop *loop;
 {
-  register int level = 1;
+  int level = 1;
   rtx insn;
   struct loop_info *loop_info = LOOP_INFO (loop);
   rtx start = loop->start;
@@ -2306,7 +2334,7 @@ prescan_loop (loop)
   loop_info->num_mem_sets = 0;
 
 
-  for (insn = start; insn && GET_CODE (insn) != CODE_LABEL; 
+  for (insn = start; insn && GET_CODE (insn) != CODE_LABEL;
        insn = PREV_INSN (insn))
     {
       if (GET_CODE (insn) == CALL_INSN)
@@ -2334,7 +2362,7 @@ prescan_loop (loop)
        }
       else if (GET_CODE (insn) == CALL_INSN)
        {
-         if (! CONST_CALL_P (insn))
+         if (! CONST_OR_PURE_CALL_P (insn))
            {
              loop_info->unknown_address_altered = 1;
              loop_info->has_nonconst_call = 1;
@@ -2482,19 +2510,6 @@ find_and_verify_loops (f, loops)
            current_loop = next_loop;
            break;
 
-         case NOTE_INSN_SETJMP:
-           /* In this case, we must invalidate our current loop and any
-              enclosing loop.  */
-           for (loop = current_loop; loop; loop = loop->outer)
-             {
-               loop->invalid = 1;
-               if (loop_dump_stream)
-                 fprintf (loop_dump_stream,
-                          "\nLoop at %d ignored due to setjmp.\n",
-                          INSN_UID (loop->start));
-             }
-           break;
-
          case NOTE_INSN_LOOP_CONT:
            current_loop->cont = insn;
            break;
@@ -2515,6 +2530,21 @@ find_and_verify_loops (f, loops)
            break;
          }
 
+      if (GET_CODE (insn) == CALL_INSN
+         && find_reg_note (insn, REG_SETJMP, NULL))
+       {
+         /* In this case, we must invalidate our current loop and any
+            enclosing loop.  */
+         for (loop = current_loop; loop; loop = loop->outer)
+           {
+             loop->invalid = 1;
+             if (loop_dump_stream)
+               fprintf (loop_dump_stream,
+                        "\nLoop at %d ignored due to setjmp.\n",
+                        INSN_UID (loop->start));
+           }
+       }
+
       /* Note that this will mark the NOTE_INSN_LOOP_END note as being in the
         enclosing loop, but this doesn't matter.  */
       uid_loop[INSN_UID (insn)] = current_loop;
@@ -2646,6 +2676,14 @@ find_and_verify_loops (f, loops)
                  = JUMP_LABEL (insn) ? JUMP_LABEL (insn) : get_last_insn ();
                struct loop *target_loop = uid_loop[INSN_UID (target)];
                rtx loc, loc2;
+               rtx tmp;
+
+               /* Search for possible garbage past the conditional jumps
+                  and look for the last barrier.  */
+               for (tmp = last_insn_to_move;
+                    tmp && GET_CODE (tmp) != CODE_LABEL; tmp = NEXT_INSN (tmp))
+                 if (GET_CODE (tmp) == BARRIER)
+                   last_insn_to_move = tmp;
 
                for (loc = target; loc; loc = PREV_INSN (loc))
                  if (GET_CODE (loc) == BARRIER
@@ -2689,7 +2727,7 @@ find_and_verify_loops (f, loops)
                        /* If no suitable BARRIER was found, create a suitable
                           one before TARGET.  Since TARGET is a fall through
                           path, we'll need to insert an jump around our block
-                          and a add a BARRIER before TARGET.
+                          and add a BARRIER before TARGET.
 
                           This creates an extra unconditional jump outside
                           the loop.  However, the benefits of removing rarely
@@ -2709,8 +2747,7 @@ find_and_verify_loops (f, loops)
 
                        /* Include the BARRIER after INSN and copy the
                           block after LOC.  */
-                       new_label = squeeze_notes (new_label,
-                                                  last_insn_to_move);
+                       squeeze_notes (&new_label, &last_insn_to_move);
                        reorder_insns (new_label, last_insn_to_move, loc);
 
                        /* All those insns are now in TARGET_LOOP.  */
@@ -2760,7 +2797,7 @@ find_and_verify_loops (f, loops)
                        if (JUMP_LABEL (insn) != 0
                            && (next_real_insn (JUMP_LABEL (insn))
                                == next_real_insn (insn)))
-                         delete_insn (insn);
+                         delete_related_insns (insn);
                      }
 
                    /* Continue the loop after where the conditional
@@ -2770,7 +2807,7 @@ find_and_verify_loops (f, loops)
                    insn = NEXT_INSN (cond_label);
 
                    if (--LABEL_NUSES (cond_label) == 0)
-                     delete_insn (cond_label);
+                     delete_related_insns (cond_label);
 
                    /* This loop will be continued with NEXT_INSN (insn).  */
                    insn = PREV_INSN (insn);
@@ -3023,13 +3060,13 @@ note_set_pseudo_multiple_uses (x, y, data)
 int
 loop_invariant_p (loop, x)
      const struct loop *loop;
-     register rtx x;
+     rtx x;
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
-  register int i;
-  register enum rtx_code code;
-  register const char *fmt;
+  int i;
+  enum rtx_code code;
+  const char *fmt;
   int conditional = 0;
   rtx mem_list_entry;
 
@@ -3127,7 +3164,7 @@ loop_invariant_p (loop, x)
        }
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            {
              int tem = loop_invariant_p (loop, XVECEXP (x, i, j));
@@ -3177,7 +3214,7 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
 
   while (count > 0)
     {
-      register enum rtx_code code;
+      enum rtx_code code;
       rtx set;
 
       p = NEXT_INSN (p);
@@ -3234,12 +3271,12 @@ all_sets_invariant_p (reg, insn, table)
      rtx reg, insn;
      short *table;
 {
-  register rtx p = insn;
-  register int regno = REGNO (reg);
+  rtx p = insn;
+  int regno = REGNO (reg);
 
   while (1)
     {
-      register enum rtx_code code;
+      enum rtx_code code;
       p = NEXT_INSN (p);
       code = GET_CODE (p);
       if (code == CODE_LABEL || code == JUMP_INSN)
@@ -3321,7 +3358,7 @@ count_one_set (regs, insn, x, last_set)
        dest = XEXP (dest, 0);
       if (GET_CODE (dest) == REG)
        {
-         register int regno = REGNO (dest);
+         int regno = REGNO (dest);
          /* If this is the first setting of this reg
             in current basic block, and it was set before,
             it must be set in two basic blocks, so it cannot
@@ -3581,7 +3618,7 @@ loop_bivs_find (loop)
   ivs->list = 0;
 
   for_each_insn_in_loop (loop, check_insn_for_bivs);
-  
+
   /* Scan ivs->list to remove all regs that proved not to be bivs.
      Make a sanity check against regs->n_times_set.  */
   for (backbl = &ivs->list, bl = *backbl; bl; bl = bl->next)
@@ -3708,8 +3745,8 @@ loop_bivs_check (loop)
 
       if ((GET_MODE (src) == GET_MODE (regno_reg_rtx[bl->regno])
           || GET_MODE (src) == VOIDmode)
-         && valid_initial_value_p (src, bl->init_insn, 
-                                   LOOP_INFO (loop)->pre_header_has_call, 
+         && valid_initial_value_p (src, bl->init_insn,
+                                   LOOP_INFO (loop)->pre_header_has_call,
                                    loop->start))
        {
          bl->initial_value = src;
@@ -3740,7 +3777,7 @@ loop_givs_find (loop)
 
 /* For each giv for which we still don't know whether or not it is
    replaceable, check to see if it is replaceable because its final value
-   can be calculated.   */
+   can be calculated.  */
 
 static void
 loop_givs_check (loop)
@@ -3792,7 +3829,7 @@ loop_biv_eliminable_p (loop, bl, threshold, insn_count)
      loop->start since these won't be affected by the value of the biv
      elsewhere in the function, so long as init_insn doesn't use the
      biv itself.  */
-  
+
   if ((REGNO_LAST_LUID (bl->regno) < INSN_LUID (loop->end)
        && bl->init_insn
        && INSN_UID (bl->init_insn) < max_uid_for_loop
@@ -3800,7 +3837,7 @@ loop_biv_eliminable_p (loop, bl, threshold, insn_count)
        && ! reg_mentioned_p (bl->biv->dest_reg, SET_SRC (bl->init_set)))
       || (bl->final_value = final_biv_value (loop, bl)))
     return maybe_eliminate_biv (loop, bl, 0, threshold,        insn_count);
-  
+
   if (loop_dump_stream)
     {
       fprintf (loop_dump_stream,
@@ -3830,12 +3867,12 @@ loop_givs_reduce (loop, bl)
       if (! v->ignore && v->same == 0)
        {
          int auto_inc_opt = 0;
-         
+
          /* If the code for derived givs immediately below has already
             allocated a new_reg, we must keep it.  */
          if (! v->new_reg)
            v->new_reg = gen_reg_rtx (v->mode);
-         
+
 #ifdef AUTO_INC_DEC
          /* If the target has auto-increment addressing modes, and
             this is an address giv, then try to put the increment
@@ -3852,7 +3889,7 @@ loop_givs_reduce (loop, bl)
              /* If other giv's have been combined with this one, then
                 this will work only if all uses of the other giv's occur
                 before this giv's insn.  This is difficult to check.
-                
+
                 We simplify this by looking for the common case where
                 there is one DEST_REG giv, and this giv's insn is the
                 last use of the dest_reg of that DEST_REG giv.  If the
@@ -3864,7 +3901,7 @@ loop_givs_reduce (loop, bl)
              if (v->combined_with)
                {
                  struct induction *other_giv = 0;
-                 
+
                  for (tv = bl->giv; tv; tv = tv->next_iv)
                    if (tv->same == v)
                      {
@@ -3892,11 +3929,11 @@ loop_givs_reduce (loop, bl)
                auto_inc_opt = -1;
              else
                auto_inc_opt = 1;
-             
+
 #ifdef HAVE_cc0
              {
                rtx prev;
-               
+
                /* We can't put an insn immediately after one setting
                   cc0, or immediately before one using cc0.  */
                if ((auto_inc_opt == 1 && sets_cc0_p (PATTERN (v->insn)))
@@ -3907,39 +3944,39 @@ loop_givs_reduce (loop, bl)
                  auto_inc_opt = 0;
              }
 #endif
-             
+
              if (auto_inc_opt)
                v->auto_inc_opt = 1;
            }
 #endif
-         
+
          /* For each place where the biv is incremented, add an insn
             to increment the new, reduced reg for the giv.  */
          for (tv = bl->biv; tv; tv = tv->next_iv)
            {
              rtx insert_before;
-             
+
              if (! auto_inc_opt)
                insert_before = tv->insn;
              else if (auto_inc_opt == 1)
                insert_before = NEXT_INSN (v->insn);
              else
                insert_before = v->insn;
-             
+
              if (tv->mult_val == const1_rtx)
                loop_iv_add_mult_emit_before (loop, tv->add_val, v->mult_val,
-                                             v->new_reg, v->new_reg, 
+                                             v->new_reg, v->new_reg,
                                              0, insert_before);
              else /* tv->mult_val == const0_rtx */
                /* A multiply is acceptable here
                   since this is presumed to be seldom executed.  */
                loop_iv_add_mult_emit_before (loop, tv->add_val, v->mult_val,
-                                             v->add_val, v->new_reg, 
+                                             v->add_val, v->new_reg,
                                              0, insert_before);
            }
-         
+
          /* Add code at loop start to initialize giv's reduced reg.  */
-         
+
          loop_iv_add_mult_hoist (loop,
                                  extend_value_for_giv (v, bl->initial_value),
                                  v->mult_val, v->add_val, v->new_reg);
@@ -3965,12 +4002,12 @@ loop_givs_dead_check (loop, bl)
       if (v->ignore
          || (v->same && v->same->ignore))
        continue;
-      
+
       if (v->giv_type == DEST_REG
          && REGNO_FIRST_UID (REGNO (v->dest_reg)) == INSN_UID (v->insn))
        {
          struct induction *v1;
-         
+
          for (v1 = bl->giv; v1; v1 = v1->next_iv)
            if (REGNO_LAST_UID (REGNO (v->dest_reg)) == INSN_UID (v1->insn))
              v->maybe_dead = 1;
@@ -3991,16 +4028,16 @@ loop_givs_rescan (loop, bl, reg_map)
     {
       if (v->same && v->same->ignore)
        v->ignore = 1;
-      
+
       if (v->ignore)
        continue;
-      
+
       /* Update expression if this was combined, in case other giv was
         replaced.  */
       if (v->same)
        v->new_reg = replace_rtx (v->new_reg,
                                  v->same->dest_reg, v->same->new_reg);
-      
+
       /* See if this register is known to be a pointer to something.  If
         so, see if we can find the alignment.  First see if there is a
         destination register that is a pointer.  If so, this shares the
@@ -4017,12 +4054,12 @@ loop_givs_rescan (loop, bl, reg_map)
               && REG_POINTER (v->src_reg))
        {
          unsigned int align = REGNO_POINTER_ALIGN (REGNO (v->src_reg));
-         
+
          if (align == 0
              || GET_CODE (v->add_val) != CONST_INT
              || INTVAL (v->add_val) % (align / BITS_PER_UNIT) != 0)
            align = 0;
-         
+
          mark_reg_pointer (v->new_reg, align);
        }
       else if (GET_CODE (v->new_reg) == REG
@@ -4030,16 +4067,16 @@ loop_givs_rescan (loop, bl, reg_map)
               && REG_POINTER (v->add_val))
        {
          unsigned int align = REGNO_POINTER_ALIGN (REGNO (v->add_val));
-         
+
          if (align == 0 || GET_CODE (v->mult_val) != CONST_INT
              || INTVAL (v->mult_val) % (align / BITS_PER_UNIT) != 0)
            align = 0;
-         
+
          mark_reg_pointer (v->new_reg, align);
        }
       else if (GET_CODE (v->new_reg) == REG && v->giv_type == DEST_ADDR)
        mark_reg_pointer (v->new_reg, 0);
-      
+
       if (v->giv_type == DEST_ADDR)
        /* Store reduced reg as the address in the memref where we found
           this giv.  */
@@ -4052,23 +4089,23 @@ loop_givs_rescan (loop, bl, reg_map)
        {
          /* Not replaceable; emit an insn to set the original giv reg from
             the reduced giv, same as above.  */
-         loop_insn_emit_after (loop, 0, v->insn, 
+         loop_insn_emit_after (loop, 0, v->insn,
                                gen_move_insn (v->dest_reg, v->new_reg));
        }
-      
+
       /* When a loop is reversed, givs which depend on the reversed
         biv, and which are live outside the loop, must be set to their
         correct final value.  This insn is only needed if the giv is
         not replaceable.  The correct final value is the same as the
         value that the giv starts the reversed loop with.  */
       if (bl->reversed && ! v->replaceable)
-       loop_iv_add_mult_sink (loop, 
+       loop_iv_add_mult_sink (loop,
                               extend_value_for_giv (v, bl->initial_value),
                               v->mult_val, v->add_val, v->dest_reg);
       else if (v->final_value)
-       loop_insn_sink_or_swim (loop, 
+       loop_insn_sink_or_swim (loop,
                                gen_move_insn (v->dest_reg, v->final_value));
-      
+
       if (loop_dump_stream)
        {
          fprintf (loop_dump_stream, "giv at %d reduced to ",
@@ -4094,7 +4131,7 @@ loop_giv_reduce_benefit (loop, bl, v, test_reg)
   PUT_MODE (test_reg, v->mode);
   add_cost = iv_add_mult_cost (bl->biv->add_val, v->mult_val,
                               test_reg, test_reg);
-  
+
   /* Reduce benefit if not replaceable, since we will insert a
      move-insn to replace the insn that calculates this giv.  Don't do
      this unless the giv is a user variable, since it will often be
@@ -4108,7 +4145,7 @@ loop_giv_reduce_benefit (loop, bl, v, test_reg)
   if (! v->replaceable && ! bl->eliminable
       && REG_USERVAR_P (v->dest_reg))
     benefit -= copy_cost;
-  
+
   /* Decrease the benefit to count the add-insns that we will insert
      to increment the reduced reg for the giv.  ??? This can
      overestimate the run-time cost of the additional insns, e.g. if
@@ -4163,7 +4200,7 @@ loop_ivs_free (loop)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *iv = ivs->list;
-  
+
   free (ivs->regs);
 
   while (iv)
@@ -4171,7 +4208,7 @@ loop_ivs_free (loop)
       struct iv_class *next = iv->next;
       struct induction *induction;
       struct induction *next_induction;
-      
+
       for (induction = iv->biv; induction; induction = next_induction)
        {
          next_induction = induction->next_iv;
@@ -4182,7 +4219,7 @@ loop_ivs_free (loop)
          next_induction = induction->next_iv;
          free (induction);
        }
-      
+
       free (iv);
       iv = next;
     }
@@ -4199,9 +4236,8 @@ loop_ivs_free (loop)
    must check regnos to make sure they are in bounds.  */
 
 static void
-strength_reduce (loop, insn_count, flags)
+strength_reduce (loop, flags)
      struct loop *loop;
-     int insn_count;
      int flags;
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
@@ -4221,6 +4257,7 @@ strength_reduce (loop, insn_count, flags)
   int reg_map_size;
   int unrolled_insn_copies = 0;
   rtx test_reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
+  int insn_count = count_insns_in_loop (loop);
 
   addr_placeholder = gen_reg_rtx (Pmode);
 
@@ -4283,11 +4320,16 @@ strength_reduce (loop, insn_count, flags)
     {
       struct induction *v;
       int benefit;
-      
+
       /* Test whether it will be possible to eliminate this biv
         provided all givs are reduced.  */
       bl->eliminable = loop_biv_eliminable_p (loop, bl, threshold, insn_count);
 
+      /* This will be true at the end, if all givs which depend on this
+        biv have been strength reduced.
+        We can't (currently) eliminate the biv unless this is so.  */
+      bl->all_reduced = 1;
+
       /* Check each extension dependent giv in this class to see if its
         root biv is safe from wrapping in the interior mode.  */
       check_ext_dependant_givs (bl, loop_info);
@@ -4295,11 +4337,6 @@ strength_reduce (loop, insn_count, flags)
       /* Combine all giv's for this iv_class.  */
       combine_givs (regs, bl);
 
-      /* This will be true at the end, if all givs which depend on this
-        biv have been strength reduced.
-        We can't (currently) eliminate the biv unless this is so.  */
-      bl->all_reduced = 1;
-
       for (v = bl->giv; v; v = v->next_iv)
        {
          struct induction *tv;
@@ -4481,6 +4518,18 @@ strength_reduce (loop, insn_count, flags)
     doloop_optimize (loop);
 #endif  /* HAVE_doloop_end  */
 
+  /* In case number of iterations is known, drop branch prediction note
+     in the branch.  Do that only in second loop pass, as loop unrolling
+     may change the number of iterations performed.  */
+  if ((flags & LOOP_BCT)
+      && loop_info->n_iterations / loop_info->unroll_number > 1)
+    {
+      int n = loop_info->n_iterations / loop_info->unroll_number;
+      predict_insn (PREV_INSN (loop->end),
+                   PRED_LOOP_ITERATIONS,
+                   REG_BR_PROB_BASE - REG_BR_PROB_BASE / n);
+    }
+
   if (loop_dump_stream)
     fprintf (loop_dump_stream, "\n");
 
@@ -4601,7 +4650,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
 
          record_giv (loop, v, p, src_reg, dest_reg, mult_val, add_val,
                      ext_val, benefit, DEST_REG, not_every_iteration,
-                     maybe_multiple, NULL_PTR);
+                     maybe_multiple, (rtx*)0);
 
        }
     }
@@ -4675,9 +4724,9 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
      rtx insn;
      int not_every_iteration, maybe_multiple;
 {
-  register int i, j;
-  register enum rtx_code code;
-  register const char *fmt;
+  int i, j;
+  enum rtx_code code;
+  const char *fmt;
 
   if (x == 0)
     return;
@@ -4710,7 +4759,7 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
        /* This code used to disable creating GIVs with mult_val == 1 and
           add_val == 0.  However, this leads to lost optimizations when
           it comes time to combine a set of related DEST_ADDR GIVs, since
-          this one would not be seen.   */
+          this one would not be seen.  */
 
        if (general_induction_var (loop, XEXP (x, 0), &src_reg, &add_val,
                                   &mult_val, &ext_val, 1, &benefit,
@@ -4871,9 +4920,12 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
   rtx set = single_set (insn);
   rtx temp;
 
-  /* Attempt to prove constantness of the values.  */
+  /* Attempt to prove constantness of the values.  Don't let simplity_rtx
+     undo the MULT canonicalization that we performed earlier.  */
   temp = simplify_rtx (add_val);
-  if (temp)
+  if (temp
+      && ! (GET_CODE (add_val) == MULT
+           && GET_CODE (temp) == ASHIFT))
     add_val = temp;
 
   v->insn = insn;
@@ -4958,12 +5010,12 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
     {
       /* The giv can be replaced outright by the reduced register only if all
         of the following conditions are true:
-        - the insn that sets the giv is always executed on any iteration
+        - the insn that sets the giv is always executed on any iteration
           on which the giv is used at all
           (there are two ways to deduce this:
            either the insn is executed on every iteration,
            or all uses follow that insn in the same basic block),
-        - the giv is not used outside the loop
+        - the giv is not used outside the loop
         - no assignments to the biv occur during the giv's lifetime.  */
 
       if (REGNO_FIRST_UID (REGNO (dest_reg)) == INSN_UID (insn)
@@ -5346,7 +5398,7 @@ update_giv_derive (loop, p)
 static int
 basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
      const struct loop *loop;
-     register rtx x;
+     rtx x;
      enum machine_mode mode;
      rtx dest_reg;
      rtx p;
@@ -5354,7 +5406,7 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
      rtx *mult_val;
      rtx **location;
 {
-  register enum rtx_code code;
+  enum rtx_code code;
   rtx *argp, arg;
   rtx insn, set = 0;
 
@@ -5447,7 +5499,7 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
       /* Fall through.  */
 
       /* Can accept constant setting of biv only when inside inner most loop.
-        Otherwise, a biv of an inner loop may be incorrectly recognized
+        Otherwise, a biv of an inner loop may be incorrectly recognized
         as a biv of the outer loop,
         causing code to be moved INTO the inner loop.  */
     case MEM:
@@ -5609,7 +5661,7 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
 \f
 /* Given an expression, X, try to form it as a linear function of a biv.
    We will canonicalize it to be of the form
-       (plus (mult (BIV) (invar_1))
+       (plus (mult (BIV) (invar_1))
              (invar_2))
    with possible degeneracies.
 
@@ -5675,7 +5727,7 @@ simplify_giv_expr (loop, x, ext_val, benefit)
          case CONST_INT:
          case USE:
            /* Adding two invariants must result in an invariant, so enclose
-              addition operation inside a USE and return it.  */
+              addition operation inside a USE and return it.  */
            if (GET_CODE (arg0) == USE)
              arg0 = XEXP (arg0, 0);
            if (GET_CODE (arg1) == USE)
@@ -6229,7 +6281,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
    it cannot possibly be a valid address, 0 is returned.
 
    To perform the computation, we note that
-       G1 = x * v + a          and
+       G1 = x * v + a          and
        G2 = y * v + b
    where `v' is the biv.
 
@@ -6320,7 +6372,10 @@ express_from_1 (a, b, mult)
     }
   else if (CONSTANT_P (a))
     {
-      return simplify_gen_binary (MINUS, GET_MODE (b) != VOIDmode ? GET_MODE (b) : GET_MODE (a), const0_rtx, a);
+      enum machine_mode mode_a = GET_MODE (a);
+      enum machine_mode mode_b = GET_MODE (b);
+      enum machine_mode mode = mode_b == VOIDmode ? mode_a : mode_b;
+      return simplify_gen_binary (MINUS, mode, b, a);
     }
   else if (GET_CODE (b) == PLUS)
     {
@@ -6630,6 +6685,7 @@ check_ext_dependant_givs (bl, loop_info)
                         INSN_UID (v->insn), why);
              }
            v->ignore = 1;
+           bl->all_reduced = 0;
          }
       }
 }
@@ -6793,6 +6849,13 @@ restart:
 
              g2->new_reg = can_combine[i * giv_count + j];
              g2->same = g1;
+             /* For destination, we now may replace by mem expression instead
+                of register.  This changes the costs considerably, so add the
+                compensation.  */
+             if (g2->giv_type == DEST_ADDR)
+               g2->benefit = (g2->benefit + reg_address_cost
+                              - address_cost (g2->new_reg,
+                              GET_MODE (g2->mem)));
              g1->combined_with++;
              g1->lifetime += g2->lifetime;
 
@@ -6892,7 +6955,7 @@ loop_regs_update (loop, seq)
            record_base_value (REGNO (SET_DEST (set)), SET_SRC (set), 0);
        }
     }
-  else 
+  else
     {
       rtx set = single_set (seq);
       if (set && GET_CODE (SET_DEST (set)) == REG)
@@ -7324,12 +7387,11 @@ check_dbra_loop (loop, insn_count)
            {
              struct induction *v;
 
-             reversible_mem_store
-               = (! loop_info->unknown_address_altered
-                  && ! loop_info->unknown_constant_address_altered
-                  && ! loop_invariant_p (loop,
-                                         XEXP (XEXP (loop_info->store_mems, 0),
-                                               0)));
+             /* If we could prove that each of the memory locations
+                written to was different, then we could reverse the
+                store -- but we don't presently have any way of
+                knowing that.  */
+             reversible_mem_store = 0;
 
              /* If the store depends on a register that is set after the
                 store, it depends on the initial value, and is thus not
@@ -7361,7 +7423,7 @@ check_dbra_loop (loop, insn_count)
           && ! loop_info->has_volatile
           && reversible_mem_store
           && (bl->giv_count + bl->biv_count + loop_info->num_mem_sets
-              + LOOP_MOVABLES (loop)->num + compare_and_branch == insn_count)
+              + num_unmoved_movables (loop) + compare_and_branch == insn_count)
           && (bl == ivs->list && bl->next == 0))
          || no_use_except_counting)
        {
@@ -7509,9 +7571,7 @@ check_dbra_loop (loop, insn_count)
 
              /* Save some info needed to produce the new insns.  */
              reg = bl->biv->dest_reg;
-             jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 1);
-             if (jump_label == pc_rtx)
-               jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 2);
+             jump_label = condjump_label (PREV_INSN (loop_end));
              new_add_val = GEN_INT (-INTVAL (bl->biv->add_val));
 
              /* Set start_value; if this is not a CONST_INT, we need
@@ -7527,21 +7587,16 @@ check_dbra_loop (loop, insn_count)
                }
              else if (GET_CODE (initial_value) == CONST_INT)
                {
-                 rtx offset = GEN_INT (-INTVAL (initial_value) - add_adjust);
                  enum machine_mode mode = GET_MODE (reg);
-                 enum insn_code icode
-                   = add_optab->handlers[(int) mode].insn_code;
-
-                 if (! (*insn_data[icode].operand[0].predicate) (reg, mode)
-                     || ! ((*insn_data[icode].operand[1].predicate)
-                           (comparison_value, mode))
-                     || ! ((*insn_data[icode].operand[2].predicate)
-                           (offset, mode)))
+                 rtx offset = GEN_INT (-INTVAL (initial_value) - add_adjust);
+                 rtx add_insn = gen_add3_insn (reg, comparison_value, offset);
+
+                 if (add_insn == 0)
                    return 0;
+
                  start_value
                    = gen_rtx_PLUS (mode, comparison_value, offset);
-                 loop_insn_hoist (loop, (GEN_FCN (icode)
-                                            (reg, comparison_value, offset)));
+                 loop_insn_hoist (loop, add_insn);
                  if (GET_CODE (comparison) == LE)
                    final_value = gen_rtx_PLUS (mode, comparison_value,
                                                GEN_INT (add_val));
@@ -7549,19 +7604,14 @@ check_dbra_loop (loop, insn_count)
              else if (! add_adjust)
                {
                  enum machine_mode mode = GET_MODE (reg);
-                 enum insn_code icode
-                   = sub_optab->handlers[(int) mode].insn_code;
-                 if (! (*insn_data[icode].operand[0].predicate) (reg, mode)
-                     || ! ((*insn_data[icode].operand[1].predicate)
-                           (comparison_value, mode))
-                     || ! ((*insn_data[icode].operand[2].predicate)
-                           (initial_value, mode)))
+                 rtx sub_insn = gen_sub3_insn (reg, comparison_value,
+                                               initial_value);
+
+                 if (sub_insn == 0)
                    return 0;
                  start_value
                    = gen_rtx_MINUS (mode, comparison_value, initial_value);
-                 loop_insn_hoist (loop, (GEN_FCN (icode)
-                                            (reg, comparison_value,
-                                             initial_value)));
+                 loop_insn_hoist (loop, sub_insn);
                }
              else
                /* We could handle the other cases too, but it'll be
@@ -7604,9 +7654,9 @@ check_dbra_loop (loop, insn_count)
                loop_insn_sink (loop, gen_move_insn (reg, final_value));
 
              /* Delete compare/branch at end of loop.  */
-             delete_insn (PREV_INSN (loop_end));
+             delete_related_insns (PREV_INSN (loop_end));
              if (compare_and_branch == 2)
-               delete_insn (first_compare);
+               delete_related_insns (first_compare);
 
              /* Add new compare/branch insn at end of loop.  */
              start_sequence ();
@@ -8056,7 +8106,7 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn)
                                 v->new_reg, 1);
 
                /* Compute value to compare against.  */
-               loop_iv_add_mult_emit_before (loop, arg, 
+               loop_iv_add_mult_emit_before (loop, arg,
                                              v->mult_val, v->add_val,
                                              tem, where_bb, where_insn);
                /* Use it in this insn.  */
@@ -8094,7 +8144,7 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn)
                                     v->new_reg, 1);
 
                    /* Compute value to compare against.  */
-                   loop_iv_add_mult_emit_before (loop, arg, 
+                   loop_iv_add_mult_emit_before (loop, arg,
                                                  v->mult_val, v->add_val,
                                                  tem, where_bb, where_insn);
                    validate_change (insn, &XEXP (x, arg_operand), tem, 1);
@@ -8130,7 +8180,7 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn)
              if (v->ignore || v->maybe_dead || v->mode != mode)
                continue;
 
-             for (tv = REG_IV_CLASS (ivs, REGNO (arg))->giv; tv; 
+             for (tv = REG_IV_CLASS (ivs, REGNO (arg))->giv; tv;
                   tv = tv->next_iv)
                if (! tv->ignore && ! tv->maybe_dead
                    && rtx_equal_p (tv->mult_val, v->mult_val)
@@ -8252,8 +8302,8 @@ update_reg_last_use (x, insn)
   /* Check for the case where INSN does not have a valid luid.  In this case,
      there is no need to modify the regno_last_uid, as this can only happen
      when code is inserted after the loop_end to set a pseudo's final value,
-     and hence this insn will never be the last use of x. 
-     ???? This comment is not correct.  See for example loop_givs_reduce.  
+     and hence this insn will never be the last use of x.
+     ???? This comment is not correct.  See for example loop_givs_reduce.
      This may insert an insn before another new insn.  */
   if (GET_CODE (x) == REG && REGNO (x) < max_reg_before_loop
       && INSN_UID (insn) < max_uid_for_loop
@@ -8263,8 +8313,8 @@ update_reg_last_use (x, insn)
     }
   else
     {
-      register int i, j;
-      register const char *fmt = GET_RTX_FORMAT (GET_CODE (x));
+      int i, j;
+      const char *fmt = GET_RTX_FORMAT (GET_CODE (x));
       for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
        {
          if (fmt[i] == 'e')
@@ -8581,7 +8631,7 @@ get_condition_for_loop (loop, x)
      const struct loop *loop;
      rtx x;
 {
-  rtx comparison = get_condition (x, NULL_PTR);
+  rtx comparison = get_condition (x, (rtx*)0);
 
   if (comparison == 0
       || ! loop_invariant_p (loop, XEXP (comparison, 0))
@@ -8701,16 +8751,12 @@ insert_loop_mem (mem, data)
    parameter may be zero, in which case this processing is not done.
 
    Set REGS->ARRAY[I].MAY_NOT_OPTIMIZE nonzero if we should not
-   optimize register I.
-
-   Store in *COUNT_PTR the number of actual instructions
-   in the loop.  We use this to decide what is worth moving out.  */
+   optimize register I.  */
 
 static void
-loop_regs_scan (loop, extra_size, count_ptr)
+loop_regs_scan (loop, extra_size)
      const struct loop *loop;
      int extra_size;
-     int *count_ptr;
 {
   struct loop_regs *regs = LOOP_REGS (loop);
   int old_nregs;
@@ -8718,7 +8764,6 @@ loop_regs_scan (loop, extra_size, count_ptr)
    basic block.  In that case, it is the insn that last set reg n.  */
   rtx *last_set;
   rtx insn;
-  int count = 0;
   int i;
 
   old_nregs = regs->num;
@@ -8728,7 +8773,7 @@ loop_regs_scan (loop, extra_size, count_ptr)
   if (regs->num >= regs->size)
     {
       regs->size = regs->num + extra_size;
-      
+
       regs->array = (struct loop_reg *)
        xrealloc (regs->array, regs->size * sizeof (*regs->array));
 
@@ -8753,8 +8798,6 @@ loop_regs_scan (loop, extra_size, count_ptr)
     {
       if (INSN_P (insn))
        {
-         ++count;
-
          /* Record registers that have exactly one use.  */
          find_single_use_in_loop (regs, insn, PATTERN (insn));
 
@@ -8767,7 +8810,7 @@ loop_regs_scan (loop, extra_size, count_ptr)
            count_one_set (regs, insn, PATTERN (insn), last_set);
          else if (GET_CODE (PATTERN (insn)) == PARALLEL)
            {
-             register int i;
+             int i;
              for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
                count_one_set (regs, insn, XVECEXP (PATTERN (insn), 0, i),
                               last_set);
@@ -8791,15 +8834,30 @@ loop_regs_scan (loop, extra_size, count_ptr)
     if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
       regs->array[i].may_not_optimize = 1;
 #endif
-  
+
   /* Set regs->array[I].n_times_set for the new registers.  */
   for (i = old_nregs; i < regs->num; i++)
     regs->array[i].n_times_set = regs->array[i].set_in_loop;
 
   free (last_set);
-  *count_ptr = count;
 }
 
+/* Returns the number of real INSNs in the LOOP.  */
+
+static int
+count_insns_in_loop (loop)
+     const struct loop *loop;
+{
+  int count = 0;
+  rtx insn;
+
+  for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
+       insn = NEXT_INSN (insn))
+    if (INSN_P (insn))
+      ++count;
+
+  return count;
+}
 
 /* Move MEMs into registers for the duration of the loop.  */
 
@@ -8811,7 +8869,7 @@ load_mems (loop)
   struct loop_regs *regs = LOOP_REGS (loop);
   int maybe_never = 0;
   int i;
-  rtx p;
+  rtx p, prev_ebb_head;
   rtx label = NULL_RTX;
   rtx end_label;
   /* Nonzero if the next instruction may never be executed.  */
@@ -8830,7 +8888,7 @@ load_mems (loop)
      never executed.  Also check if there is a goto out of the loop other
      than right after the end of the loop.  */
   for (p = next_insn_in_loop (loop, loop->scan_start);
-       p != NULL_RTX && ! maybe_never;
+       p != NULL_RTX;
        p = next_insn_in_loop (loop, p))
     {
       if (GET_CODE (p) == CODE_LABEL)
@@ -8850,10 +8908,13 @@ load_mems (loop)
          /* If this is a jump outside of the loop but not right
             after the end of the loop, we would have to emit new fixup
             sequences for each such label.  */
-         if (JUMP_LABEL (p) != end_label
-             && (INSN_UID (JUMP_LABEL (p)) >= max_uid_for_loop
-                 || INSN_LUID (JUMP_LABEL (p)) < INSN_LUID (loop->start)
-                 || INSN_LUID (JUMP_LABEL (p)) > INSN_LUID (loop->end)))
+         if (/* If we can't tell where control might go when this
+                JUMP_INSN is executed, we must be conservative.  */
+             !JUMP_LABEL (p)
+             || (JUMP_LABEL (p) != end_label
+                 && (INSN_UID (JUMP_LABEL (p)) >= max_uid_for_loop
+                     || INSN_LUID (JUMP_LABEL (p)) < INSN_LUID (loop->start)
+                     || INSN_LUID (JUMP_LABEL (p)) > INSN_LUID (loop->end))))
            return;
 
          if (!any_condjump_p (p))
@@ -8873,6 +8934,7 @@ load_mems (loop)
        PREV_INSN (p) && GET_CODE (p) != CODE_LABEL;
        p = PREV_INSN (p))
     ;
+  prev_ebb_head = p;
 
   cselib_init ();
 
@@ -8963,7 +9025,7 @@ load_mems (loop)
       loop_info->mems[i].reg = reg;
 
       /* Now, replace all references to the MEM with the
-        corresponding pesudos.  */
+        corresponding pseudos.  */
       maybe_never = 0;
       for (p = next_insn_in_loop (loop, loop->scan_start);
           p != NULL_RTX;
@@ -9034,7 +9096,7 @@ load_mems (loop)
                  if (CONSTANT_P (equiv->loc))
                    const_equiv = equiv;
                  else if (GET_CODE (equiv->loc) == REG
-                          /* Extending hard register lifetimes cuases crash
+                          /* Extending hard register lifetimes causes crash
                              on SRC targets.  Doing so on non-SRC is
                              probably also not good idea, since we most
                              probably have pseudoregister equivalence as
@@ -9060,8 +9122,19 @@ load_mems (loop)
              if (best_equiv)
                best = copy_rtx (best_equiv->loc);
            }
+
          set = gen_move_insn (reg, best);
          set = loop_insn_hoist (loop, set);
+         if (REG_P (best))
+           {
+             for (p = prev_ebb_head; p != loop->start; p = NEXT_INSN (p))
+               if (REGNO_LAST_UID (REGNO (best)) == INSN_UID (p))
+                 {
+                   REGNO_LAST_UID (REGNO (best)) = INSN_UID (set);
+                   break;
+                 }
+           }
+
          if (const_equiv)
            REG_NOTES (set) = gen_rtx_EXPR_LIST (REG_EQUAL,
                                                 copy_rtx (const_equiv->loc),
@@ -9214,7 +9287,16 @@ try_copy_prop (loop, replacement, regno)
          arg.set_seen = 0;
          note_stores (PATTERN (insn), note_reg_stored, &arg);
          if (arg.set_seen)
-           break;
+           {
+             rtx note = find_reg_note (insn, REG_EQUAL, NULL);
+
+             /* It is possible that we've turned previously valid REG_EQUAL to
+                invalid, as we change the REGNO to REPLACEMENT and unlike REGNO,
+                REPLACEMENT is modified, we get different meaning.  */
+             if (note && reg_mentioned_p (replacement, XEXP (note, 0)))
+               remove_note (insn, note);
+             break;
+           }
        }
     }
   if (! init_insn)
@@ -9225,17 +9307,51 @@ try_copy_prop (loop, replacement, regno)
        fprintf (loop_dump_stream, "  Replaced reg %d", regno);
       if (store_is_first && replaced_last)
        {
-         PUT_CODE (init_insn, NOTE);
-         NOTE_LINE_NUMBER (init_insn) = NOTE_INSN_DELETED;
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream, ", deleting init_insn (%d)",
-                    INSN_UID (init_insn));
+         rtx first;
+         rtx retval_note;
+
+         /* Assume we're just deleting INIT_INSN.  */
+         first = init_insn;
+         /* Look for REG_RETVAL note.  If we're deleting the end of
+            the libcall sequence, the whole sequence can go.  */
+         retval_note = find_reg_note (init_insn, REG_RETVAL, NULL_RTX);
+         /* If we found a REG_RETVAL note, find the first instruction
+            in the sequence.  */
+         if (retval_note)
+           first = XEXP (retval_note, 0);
+
+         /* Delete the instructions.  */
+         loop_delete_insns (first, init_insn);
        }
       if (loop_dump_stream)
        fprintf (loop_dump_stream, ".\n");
     }
 }
 
+/* Replace all the instructions from FIRST up to and including LAST
+   with NOTE_INSN_DELETED notes.  */
+
+static void
+loop_delete_insns (first, last)
+     rtx first;
+     rtx last;
+{
+  while (1)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream, ", deleting init_insn (%d)",
+                INSN_UID (first));
+      delete_insn (first);
+
+      /* If this was the LAST instructions we're supposed to delete,
+        we're done.  */
+      if (first == last)
+       break;
+
+      first = NEXT_INSN (first);
+    }
+}
+
 /* Try to replace occurrences of pseudo REGNO with REPLACEMENT within
    loop LOOP if the order of the sets of these registers can be
    swapped.  There must be exactly one insn within the loop that sets
@@ -9267,7 +9383,7 @@ try_swap_copy_prop (loop, replacement, regno)
        break;
     }
 
-  if (set)
+  if (insn != NULL_RTX)
     {
       rtx prev_insn;
       rtx prev_set;
@@ -9617,7 +9733,7 @@ loop_iv_class_dump (bl, file, verbose)
   /* List the givs.  */
   for (i = 0, v = bl->giv; v; v = v->next_iv, i++)
     {
-      fprintf (file, " Giv%d: insn %d, benefit %d, ", 
+      fprintf (file, " Giv%d: insn %d, benefit %d, ",
               i, INSN_UID (v->insn), v->benefit);
       if (v->giv_type == DEST_ADDR)
          print_simple_rtl (file, v->mem);
@@ -9645,7 +9761,7 @@ loop_biv_dump (v, file, verbose)
 
   if (verbose && v->final_value)
     {
-      fputc ('\n', file);  
+      fputc ('\n', file);
       fprintf (file, " final ");
       print_simple_rtl (file, v->final_value);
     }
@@ -9665,22 +9781,22 @@ loop_giv_dump (v, file, verbose)
 
   if (v->giv_type == DEST_REG)
     fprintf (file, "Giv %d: insn %d",
-            REGNO (v->dest_reg),  INSN_UID (v->insn)); 
+            REGNO (v->dest_reg),  INSN_UID (v->insn));
   else
     fprintf (file, "Dest address: insn %d",
             INSN_UID (v->insn));
-  
+
   fprintf (file, " src reg %d benefit %d",
           REGNO (v->src_reg), v->benefit);
   fprintf (file, " lifetime %d",
           v->lifetime);
-  
+
   if (v->replaceable)
     fprintf (file, " replaceable");
-  
+
   if (v->no_const_addval)
     fprintf (file, " ncav");
-  
+
   if (v->ext_dependant)
     {
       switch (GET_CODE (v->ext_dependant))
@@ -9699,22 +9815,22 @@ loop_giv_dump (v, file, verbose)
        }
     }
 
-  fputc ('\n', file);  
+  fputc ('\n', file);
   fprintf (file, " mult ");
   print_simple_rtl (file, v->mult_val);
 
-  fputc ('\n', file);  
+  fputc ('\n', file);
   fprintf (file, " add  ");
   print_simple_rtl (file, v->add_val);
 
   if (verbose && v->final_value)
     {
-      fputc ('\n', file);  
+      fputc ('\n', file);
       fprintf (file, " final ");
       print_simple_rtl (file, v->final_value);
     }
 
-  fputc ('\n', file);  
+  fputc ('\n', file);
 }