OSDN Git Service

2006-02-20 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / loop.c
index ded07ef..dc9d3a0 100644 (file)
@@ -1,6 +1,7 @@
 /* Perform various loop optimizations, including strength reduction.
-   Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995,
+   1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +17,8 @@ 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, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /* This is the loop optimization pass of the compiler.
    It finds invariant computations within loops and moves them
@@ -65,6 +66,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "optabs.h"
 #include "cfgloop.h"
 #include "ggc.h"
+#include "timevar.h"
+#include "tree-pass.h"
 
 /* Get the loop info pointer of a loop.  */
 #define LOOP_INFO(LOOP) ((struct loop_info *) (LOOP)->aux)
@@ -82,8 +85,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    of an insn added during loop, since these don't have LUIDs.  */
 
 #define INSN_LUID(INSN)                        \
-  (INSN_UID (INSN) < max_uid_for_loop ? uid_luid[INSN_UID (INSN)] \
-   : (abort (), -1))
+  (gcc_assert (INSN_UID (INSN) < max_uid_for_loop), uid_luid[INSN_UID (INSN)])
 
 #define REGNO_FIRST_LUID(REGNO)                        \
   (REGNO_FIRST_UID (REGNO) < max_uid_for_loop  \
@@ -424,7 +426,7 @@ struct loop_info
 #ifndef HAVE_prefetch
 #define HAVE_prefetch 0
 #define CODE_FOR_prefetch 0
-#define gen_prefetch(a,b,c) (abort(), NULL_RTX)
+#define gen_prefetch(a,b,c) (gcc_unreachable (), NULL_RTX)
 #endif
 
 /* Give up the prefetch optimizations once we exceed a given threshold.
@@ -588,8 +590,6 @@ struct movable
 };
 
 
-static FILE *loop_dump_stream;
-
 /* Forward declarations.  */
 
 static void invalidate_loops_containing_label (rtx);
@@ -652,6 +652,14 @@ static void record_giv (const struct loop *, struct induction *, rtx, rtx,
                        rtx, rtx, rtx, rtx, int, enum g_types, int, int,
                        rtx *);
 static void update_giv_derive (const struct loop *, rtx);
+static HOST_WIDE_INT get_monotonic_increment (struct iv_class *);
+static bool biased_biv_fits_mode_p (const struct loop *, struct iv_class *,
+                                   HOST_WIDE_INT, enum machine_mode,
+                                   unsigned HOST_WIDE_INT);
+static bool biv_fits_mode_p (const struct loop *, struct iv_class *,
+                            HOST_WIDE_INT, enum machine_mode, bool);
+static bool extension_within_bounds_p (const struct loop *, struct iv_class *,
+                                      HOST_WIDE_INT, rtx);
 static void check_ext_dependent_givs (const struct loop *, struct iv_class *);
 static int basic_induction_var (const struct loop *, rtx, enum machine_mode,
                                rtx, rtx, rtx *, rtx *, rtx **);
@@ -789,12 +797,10 @@ compute_luids (rtx start, rtx end, int prev_luid)
 }
 \f
 /* Entry point of this file.  Perform loop optimization
-   on the current function.  F is the first insn of the function
-   and DUMPFILE is a stream for output of a trace of actions taken
-   (or 0 if none should be output).  */
+   on the current function.  F is the first insn of the function.  */
 
-void
-loop_optimize (rtx f, FILE *dumpfile, int flags)
+static void
+loop_optimize (rtx f, int flags)
 {
   rtx insn;
   int i;
@@ -802,8 +808,6 @@ loop_optimize (rtx f, FILE *dumpfile, int flags)
   struct loops *loops = &loops_data;
   struct loop_info *loops_info;
 
-  loop_dump_stream = dumpfile;
-
   init_recog_no_volatile ();
 
   max_reg_before_loop = max_reg_num ();
@@ -831,25 +835,25 @@ loop_optimize (rtx f, FILE *dumpfile, int flags)
      Leave some space for labels allocated by find_and_verify_loops.  */
   max_uid_for_loop = get_max_uid () + 1 + max_loop_num * 32;
 
-  uid_luid = xcalloc (max_uid_for_loop, sizeof (int));
-  uid_loop = xcalloc (max_uid_for_loop, sizeof (struct loop *));
+  uid_luid = XCNEWVEC (int, max_uid_for_loop);
+  uid_loop = XCNEWVEC (struct loop *, max_uid_for_loop);
 
   /* Allocate storage for array of loops.  */
-  loops->array = xcalloc (loops->num, sizeof (struct loop));
+  loops->array = XCNEWVEC (struct loop, loops->num);
 
   /* Find and process each loop.
      First, find them, and record them in order of their beginnings.  */
   find_and_verify_loops (f, loops);
 
   /* Allocate and initialize auxiliary loop information.  */
-  loops_info = xcalloc (loops->num, sizeof (struct loop_info));
+  loops_info = XCNEWVEC (struct loop_info, loops->num);
   for (i = 0; i < (int) loops->num; i++)
     loops->array[i].aux = loops_info + i;
 
   /* Now find all register lifetimes.  This must be done after
      find_and_verify_loops, because it might reorder the insns in the
      function.  */
-  reg_scan (f, max_reg_before_loop, 1);
+  reg_scan (f, max_reg_before_loop);
 
   /* This must occur after reg_scan so that registers created by gcse
      will have entries in the register tables.
@@ -860,8 +864,7 @@ loop_optimize (rtx f, FILE *dumpfile, int flags)
 
   /* See if we went too far.  Note that get_max_uid already returns
      one more that the maximum uid of all insn.  */
-  if (get_max_uid () > max_uid_for_loop)
-    abort ();
+  gcc_assert (get_max_uid () <= max_uid_for_loop);
   /* Now reset it to the actual size we need.  See above.  */
   max_uid_for_loop = get_max_uid ();
 
@@ -1082,8 +1085,8 @@ scan_loop (struct loop *loop, int flags)
   if (INSN_UID (loop->scan_start) >= max_uid_for_loop
       || !LABEL_P (loop->scan_start))
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream, "\nLoop from %d to %d is phony.\n\n",
+      if (dump_file)
+       fprintf (dump_file, "\nLoop from %d to %d is phony.\n\n",
                 INSN_UID (loop_start), INSN_UID (loop_end));
       return;
     }
@@ -1094,8 +1097,8 @@ scan_loop (struct loop *loop, int flags)
   loop_regs_scan (loop, loop_info->mems_idx + 16);
   insn_count = count_insns_in_loop (loop);
 
-  if (loop_dump_stream)
-    fprintf (loop_dump_stream, "\nLoop from %d to %d: %d real insns.\n",
+  if (dump_file)
+    fprintf (dump_file, "\nLoop from %d to %d: %d real insns.\n",
             INSN_UID (loop_start), INSN_UID (loop_end), insn_count);
 
   /* Scan through the loop finding insns that are safe to move.
@@ -1119,12 +1122,16 @@ scan_loop (struct loop *loop, int flags)
        in_libcall--;
       if (NONJUMP_INSN_P (p))
        {
+         /* Do not scan past an optimization barrier.  */
+         if (GET_CODE (PATTERN (p)) == ASM_INPUT)
+           break;
          temp = find_reg_note (p, REG_LIBCALL, NULL_RTX);
          if (temp)
            in_libcall++;
          if (! in_libcall
              && (set = single_set (p))
              && REG_P (SET_DEST (set))
+             && SET_DEST (set) != frame_pointer_rtx
 #ifdef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
              && SET_DEST (set) != pic_offset_table_rtx
 #endif
@@ -1215,6 +1222,12 @@ scan_loop (struct loop *loop, int flags)
              if (GET_MODE_CLASS (GET_MODE (SET_DEST (set))) == MODE_CC
                  && CONSTANT_P (src))
                ;
+#ifdef STACK_REGS
+             /* Don't hoist constant pool constants into stack regs. */
+             else if (IS_STACK_MODE (GET_MODE (SET_SRC (set)))
+                      && constant_pool_constant_p (SET_SRC (set)))
+               ;
+#endif
              /* 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
@@ -1225,13 +1238,15 @@ scan_loop (struct loop *loop, int flags)
                 - with -Os (this certainly increases size),
                 - if the mode doesn't support copy operations (obviously),
                 - if the source is already a reg (the motion will gain nothing),
-                - if the source is a legitimate constant (likewise).  */
+                - if the source is a legitimate constant (likewise),
+                - if the dest is a hard register (may be unrecognizable).  */
              else if (insert_temp
                       && (optimize_size
                           || ! can_copy_p (GET_MODE (SET_SRC (set)))
                           || REG_P (SET_SRC (set))
                           || (CONSTANT_P (SET_SRC (set))
-                              && LEGITIMATE_CONSTANT_P (SET_SRC (set)))))
+                              && LEGITIMATE_CONSTANT_P (SET_SRC (set)))
+                          || REGNO (SET_DEST (set)) < FIRST_PSEUDO_REGISTER))
                ;
              else if ((tem = loop_invariant_p (loop, src))
                       && (dependencies == 0
@@ -1253,12 +1268,13 @@ scan_loop (struct loop *loop, int flags)
                {
                  struct movable *m;
                  int regno = REGNO (SET_DEST (set));
+                 rtx user, user_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
-                    we move one of them outside the loop.  For large loops,
-                    this can lose.  The most common case of this is the address
-                    of a function being called.
+                 /* 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 we move one of them outside the loop.  For
+                    large loops, this can lose.  The most common case of
+                    this is the address of a function being called.
 
                     Therefore, if this register is marked as being used
                     exactly once if we are in a loop with calls
@@ -1266,41 +1282,44 @@ scan_loop (struct loop *loop, int flags)
                     this register with the source of this SET.  If we can,
                     delete this insn.
 
-                    Don't do this if P has a REG_RETVAL note or if we have
-                    SMALL_REGISTER_CLASSES and SET_SRC is a hard register.  */
+                    Don't do this if:
+                     (1) P has a REG_RETVAL note or
+                     (2) if we have SMALL_REGISTER_CLASSES and
+                       (a) SET_SRC is a hard register or
+                       (b) the destination of the user is a hard register.  */
 
                  if (loop_info->has_call
-                     && regs->array[regno].single_usage != 0
-                     && regs->array[regno].single_usage != const0_rtx
+                     && regno >= FIRST_PSEUDO_REGISTER 
+                     && (user = regs->array[regno].single_usage) != NULL
+                     && user != const0_rtx
                      && REGNO_FIRST_UID (regno) == INSN_UID (p)
-                     && (REGNO_LAST_UID (regno)
-                         == INSN_UID (regs->array[regno].single_usage))
+                     && REGNO_LAST_UID (regno) == INSN_UID (user)
                      && 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
-                         || (! (REG_P (SET_SRC (set))
-                                && (REGNO (SET_SRC (set))
-                                    < FIRST_PSEUDO_REGISTER))))
-                     && regno >= FIRST_PSEUDO_REGISTER 
+                     && (!SMALL_REGISTER_CLASSES
+                         || !REG_P (SET_SRC (set))
+                         || !HARD_REGISTER_P (SET_SRC (set)))
+                     && (!SMALL_REGISTER_CLASSES
+                         || !NONJUMP_INSN_P (user)
+                         || !(user_set = single_set (user))
+                         || !REG_P (SET_DEST (user_set))
+                         || !HARD_REGISTER_P (SET_DEST (user_set)))
                      /* This test is not redundant; SET_SRC (set) might be
                         a call-clobbered register and the life of REGNO
                         might span a call.  */
-                     && ! modified_between_p (SET_SRC (set), p,
-                                              regs->array[regno].single_usage)
-                     && no_labels_between_p (p,
-                                             regs->array[regno].single_usage)
-                     && validate_replace_rtx (SET_DEST (set), SET_SRC (set),
-                                              regs->array[regno].single_usage))
+                     && ! modified_between_p (SET_SRC (set), p, user)
+                     && no_labels_between_p (p, user)
+                     && validate_replace_rtx (SET_DEST (set),
+                                              SET_SRC (set), user))
                    {
                      /* Replace any usage in a REG_EQUAL note.  Must copy
                         the new source, so that we don't get rtx sharing
                         between the SET_SOURCE and REG_NOTES of insn p.  */
-                     REG_NOTES (regs->array[regno].single_usage)
-                       = (replace_rtx
-                          (REG_NOTES (regs->array[regno].single_usage),
-                           SET_DEST (set), copy_rtx (SET_SRC (set))));
+                     REG_NOTES (user)
+                       = replace_rtx (REG_NOTES (user), SET_DEST (set),
+                                      copy_rtx (SET_SRC (set)));
 
                      delete_insn (p);
                      for (i = 0; i < LOOP_REGNO_NREGS (regno, SET_DEST (set));
@@ -1309,7 +1328,7 @@ scan_loop (struct loop *loop, int flags)
                      continue;
                    }
 
-                 m = xmalloc (sizeof (struct movable));
+                 m = XNEW (struct movable);
                  m->next = 0;
                  m->insn = p;
                  m->set_src = src;
@@ -1397,7 +1416,7 @@ scan_loop (struct loop *loop, int flags)
                  if (regs->array[regno].set_in_loop == 2)
                    {
                      struct movable *m;
-                     m = xmalloc (sizeof (struct movable));
+                     m = XNEW (struct movable);
                      m->next = 0;
                      m->insn = p;
                      m->set_dest = SET_DEST (set);
@@ -1834,7 +1853,7 @@ static void
 combine_movables (struct loop_movables *movables, struct loop_regs *regs)
 {
   struct movable *m;
-  char *matched_regs = xmalloc (regs->num);
+  char *matched_regs = XNEWVEC (char, regs->num);
   enum machine_mode mode;
 
   /* Regs that are set more than once are not allowed to match
@@ -1868,19 +1887,7 @@ combine_movables (struct loop_movables *movables, struct loop_regs *regs)
              && !m1->partial
              && (matched_regs[m1->regno]
                  ||
-                 (
-                  /* Can combine regs with different modes loaded from the
-                     same constant only if the modes are the same or
-                     if both are integer modes with M wider or the same
-                     width as M1.  The check for integer is redundant, but
-                     safe, since the only case of differing destination
-                     modes with equal sources is when both sources are
-                     VOIDmode, i.e., CONST_INT.  */
-                  (GET_MODE (m->set_dest) == GET_MODE (m1->set_dest)
-                   || (GET_MODE_CLASS (GET_MODE (m->set_dest)) == MODE_INT
-                       && GET_MODE_CLASS (GET_MODE (m1->set_dest)) == MODE_INT
-                       && (GET_MODE_BITSIZE (GET_MODE (m->set_dest))
-                           >= GET_MODE_BITSIZE (GET_MODE (m1->set_dest)))))
+                 (GET_MODE (m->set_dest) == GET_MODE (m1->set_dest)
                   /* See if the source of M1 says it matches M.  */
                   && ((REG_P (m1->set_src)
                        && matched_regs[REGNO (m1->set_src)])
@@ -2044,14 +2051,26 @@ rtx_equal_for_loop_p (rtx x, rtx y, struct loop_movables *movables,
   if (GET_MODE (x) != GET_MODE (y))
     return 0;
 
-  /* These three types of rtx's can be compared nonrecursively.  */
-  if (code == REG)
-    return (REGNO (x) == REGNO (y) || regs_match_p (x, y, movables));
+  /* These types of rtx's can be compared nonrecursively.  */
+  switch (code)
+    {
+    case PC:
+    case CC0:
+    case CONST_INT:
+    case CONST_DOUBLE:
+      return 0;
 
-  if (code == LABEL_REF)
-    return XEXP (x, 0) == XEXP (y, 0);
-  if (code == SYMBOL_REF)
-    return XSTR (x, 0) == XSTR (y, 0);
+    case REG:
+      return (REGNO (x) == REGNO (y) || regs_match_p (x, y, movables));
+
+    case LABEL_REF:
+      return XEXP (x, 0) == XEXP (y, 0);
+    case SYMBOL_REF:
+      return XSTR (x, 0) == XSTR (y, 0);
+
+    default:
+      break;
+    }
 
   /* Compare the elements.  If any pair of corresponding elements
      fail to match, return 0 for the whole things.  */
@@ -2105,7 +2124,7 @@ rtx_equal_for_loop_p (rtx x, rtx y, struct loop_movables *movables,
             contain anything but integers and other rtx's,
             except for within LABEL_REFs and SYMBOL_REFs.  */
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
   return 1;
@@ -2169,34 +2188,34 @@ move_movables (struct loop *loop, struct loop_movables *movables,
   /* Map of pseudo-register replacements to handle combining
      when we move several insns that load the same value
      into different pseudo-registers.  */
-  rtx *reg_map = xcalloc (nregs, sizeof (rtx));
-  char *already_moved = xcalloc (nregs, sizeof (char));
+  rtx *reg_map = XCNEWVEC (rtx, nregs);
+  char *already_moved = XCNEWVEC (char, nregs);
 
   for (m = movables->head; m; m = m->next)
     {
       /* Describe this movable insn.  */
 
-      if (loop_dump_stream)
+      if (dump_file)
        {
-         fprintf (loop_dump_stream, "Insn %d: regno %d (life %d), ",
+         fprintf (dump_file, "Insn %d: regno %d (life %d), ",
                   INSN_UID (m->insn), m->regno, m->lifetime);
          if (m->consec > 0)
-           fprintf (loop_dump_stream, "consec %d, ", m->consec);
+           fprintf (dump_file, "consec %d, ", m->consec);
          if (m->cond)
-           fprintf (loop_dump_stream, "cond ");
+           fprintf (dump_file, "cond ");
          if (m->force)
-           fprintf (loop_dump_stream, "force ");
+           fprintf (dump_file, "force ");
          if (m->global)
-           fprintf (loop_dump_stream, "global ");
+           fprintf (dump_file, "global ");
          if (m->done)
-           fprintf (loop_dump_stream, "done ");
+           fprintf (dump_file, "done ");
          if (m->move_insn)
-           fprintf (loop_dump_stream, "move-insn ");
+           fprintf (dump_file, "move-insn ");
          if (m->match)
-           fprintf (loop_dump_stream, "matches %d ",
+           fprintf (dump_file, "matches %d ",
                     INSN_UID (m->match->insn));
          if (m->forces)
-           fprintf (loop_dump_stream, "forces %d ",
+           fprintf (dump_file, "forces %d ",
                     INSN_UID (m->forces->insn));
        }
 
@@ -2224,11 +2243,11 @@ move_movables (struct loop *loop, struct loop_movables *movables,
          p = m->insn;
          regno = m->regno;
 
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream, "savings %d ", savings);
+         if (dump_file)
+           fprintf (dump_file, "savings %d ", savings);
 
-         if (regs->array[regno].moved_once && loop_dump_stream)
-           fprintf (loop_dump_stream, "halved since already moved ");
+         if (regs->array[regno].moved_once && dump_file)
+           fprintf (dump_file, "halved since already moved ");
 
          /* An insn MUST be moved if we already moved something else
             which is safe only if this one is moved too: that is,
@@ -2286,8 +2305,8 @@ move_movables (struct loop *loop, struct loop_movables *movables,
                  if (new_start == 0)
                    new_start = i1;
 
-                 if (loop_dump_stream)
-                   fprintf (loop_dump_stream, " moved to %d", INSN_UID (i1));
+                 if (dump_file)
+                   fprintf (dump_file, " moved to %d", INSN_UID (i1));
                }
              /* If we are to re-generate the item being moved with a
                 new move insn, first delete what we have and then emit
@@ -2298,21 +2317,26 @@ move_movables (struct loop *loop, struct loop_movables *movables,
 
                  for (count = m->consec; count >= 0; count--)
                    {
-                     /* If this is the first insn of a library call sequence,
-                        something is very wrong.  */
-                     if (!NOTE_P (p)
-                         && (temp = find_reg_note (p, REG_LIBCALL, NULL_RTX)))
-                       abort ();
-
-                     /* If this is the last insn of a libcall sequence, then
-                        delete every insn in the sequence except the last.
-                        The last insn is handled in the normal manner.  */
-                     if (!NOTE_P (p)
-                         && (temp = find_reg_note (p, REG_RETVAL, NULL_RTX)))
+                     if (!NOTE_P (p))
                        {
-                         temp = XEXP (temp, 0);
-                         while (temp != p)
-                           temp = delete_insn (temp);
+                         /* If this is the first insn of a library
+                            call sequence, something is very
+                            wrong.  */
+                         gcc_assert (!find_reg_note
+                                     (p, REG_LIBCALL, NULL_RTX));
+
+                         /* If this is the last insn of a libcall
+                            sequence, then delete every insn in the
+                            sequence except the last.  The last insn
+                            is handled in the normal manner.  */
+                         temp = find_reg_note (p, REG_RETVAL, NULL_RTX);
+                         
+                         if (temp)
+                           {
+                             temp = XEXP (temp, 0);
+                             while (temp != p)
+                               temp = delete_insn (temp);
+                           }
                        }
 
                      temp = p;
@@ -2353,8 +2377,8 @@ move_movables (struct loop *loop, struct loop_movables *movables,
                                         m->is_equiv ? REG_EQUIV : REG_EQUAL,
                                         m->set_src);
 
-                 if (loop_dump_stream)
-                   fprintf (loop_dump_stream, " moved to %d", INSN_UID (i1));
+                 if (dump_file)
+                   fprintf (dump_file, " moved to %d", INSN_UID (i1));
 
                  /* The more regs we move, the less we like moving them.  */
                  threshold -= 3;
@@ -2476,8 +2500,7 @@ move_movables (struct loop *loop, struct loop_movables *movables,
                                        << GET_MODE_BITSIZE (m->savemode)))
                                      - 1),
                             reg, 1, OPTAB_LIB_WIDEN);
-                         if (tem == 0)
-                           abort ();
+                         gcc_assert (tem);
                          if (tem != reg)
                            emit_move_insn (reg, tem);
                          sequence = get_insns ();
@@ -2514,8 +2537,7 @@ move_movables (struct loop *loop, struct loop_movables *movables,
                        }
                      else if (m->insert_temp)
                        {
-                         rtx *reg_map2 = xcalloc (REGNO (newreg),
-                                                  sizeof(rtx));
+                         rtx *reg_map2 = XCNEWVEC (rtx, REGNO(newreg));
                          reg_map2 [m->regno] = newreg;
 
                          i1 = loop_insn_hoist (loop, copy_rtx (PATTERN (p)));
@@ -2544,8 +2566,8 @@ move_movables (struct loop *loop, struct loop_movables *movables,
                      if (new_start == 0)
                        new_start = i1;
 
-                     if (loop_dump_stream)
-                       fprintf (loop_dump_stream, " moved to %d",
+                     if (dump_file)
+                       fprintf (dump_file, " moved to %d",
                                 INSN_UID (i1));
 
                      /* If library call, now fix the REG_NOTES that contain
@@ -2628,23 +2650,7 @@ move_movables (struct loop *loop, struct loop_movables *movables,
                    {
                      rtx temp;
 
-                     /* Schedule the reg loaded by M1
-                        for replacement so that shares the reg of M.
-                        If the modes differ (only possible in restricted
-                        circumstances, make a SUBREG.
-
-                        Note this assumes that the target dependent files
-                        treat REG and SUBREG equally, including within
-                        GO_IF_LEGITIMATE_ADDRESS and in all the
-                        predicates since we never verify that replacing the
-                        original register with a SUBREG results in a
-                        recognizable insn.  */
-                     if (GET_MODE (m->set_dest) == GET_MODE (m1->set_dest))
-                       reg_map[m1->regno] = m->set_dest;
-                     else
-                       reg_map[m1->regno]
-                         = gen_lowpart_common (GET_MODE (m1->set_dest),
-                                               m->set_dest);
+                     reg_map[m1->regno] = m->set_dest;
 
                      /* Get rid of the matching insn
                         and prevent further processing of it.  */
@@ -2673,14 +2679,14 @@ move_movables (struct loop *loop, struct loop_movables *movables,
                        }
                    }
            }
-         else if (loop_dump_stream)
-           fprintf (loop_dump_stream, "not desirable");
+         else if (dump_file)
+           fprintf (dump_file, "not desirable");
        }
-      else if (loop_dump_stream && !m->match)
-       fprintf (loop_dump_stream, "not safe");
+      else if (dump_file && !m->match)
+       fprintf (dump_file, "not safe");
 
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream, "\n");
+      if (dump_file)
+       fprintf (dump_file, "\n");
     }
 
   if (new_start == 0)
@@ -2765,8 +2771,7 @@ replace_call_address (rtx x, rtx reg, rtx addr)
     case MEM:
       /* If this MEM uses a reg other than the one we expected,
         something is wrong.  */
-      if (XEXP (x, 0) != reg)
-       abort ();
+      gcc_assert (XEXP (x, 0) == reg);
       XEXP (x, 0) = addr;
       return;
 
@@ -3079,8 +3084,7 @@ find_and_verify_loops (rtx f, struct loops *loops)
            break;
 
          case NOTE_INSN_LOOP_END:
-           if (! current_loop)
-             abort ();
+           gcc_assert (current_loop);
 
            current_loop->end = insn;
            current_loop = current_loop->outer;
@@ -3098,8 +3102,8 @@ find_and_verify_loops (rtx f, struct loops *loops)
          for (loop = current_loop; loop; loop = loop->outer)
            {
              loop->invalid = 1;
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream,
+             if (dump_file)
+               fprintf (dump_file,
                         "\nLoop at %d ignored due to setjmp.\n",
                         INSN_UID (loop->start));
            }
@@ -3268,6 +3272,7 @@ find_and_verify_loops (rtx f, struct loops *loops)
                    if (invert_jump (p, new_label, 1))
                      {
                        rtx q, r;
+                       bool only_notes;
 
                        /* If no suitable BARRIER was found, create a suitable
                           one before TARGET.  Since TARGET is a fall through
@@ -3292,8 +3297,10 @@ find_and_verify_loops (rtx f, struct loops *loops)
 
                        /* Include the BARRIER after INSN and copy the
                           block after LOC.  */
-                       if (squeeze_notes (&new_label, &last_insn_to_move))
-                         abort ();
+                       only_notes = squeeze_notes (&new_label,
+                                                   &last_insn_to_move);
+                       gcc_assert (!only_notes);
+                       
                        reorder_insns (new_label, last_insn_to_move, loc);
 
                        /* All those insns are now in TARGET_LOOP.  */
@@ -3328,8 +3335,7 @@ find_and_verify_loops (rtx f, struct loops *loops)
 
                            /* If we didn't find it, then something is
                               wrong.  */
-                           if (! r)
-                             abort ();
+                           gcc_assert (r);
                          }
 
                        /* P is now a jump outside the loop, so it must be put
@@ -3458,8 +3464,8 @@ mark_loop_jump (rtx x, struct loop *loop)
              return;
 
          /* If we get here, we know we need to invalidate a loop.  */
-         if (loop_dump_stream && ! dest_loop->invalid)
-           fprintf (loop_dump_stream,
+         if (dump_file && ! dest_loop->invalid)
+           fprintf (dump_file,
                     "\nLoop at %d ignored due to multiple entry points.\n",
                     INSN_UID (dest_loop->start));
 
@@ -3498,8 +3504,8 @@ mark_loop_jump (rtx x, struct loop *loop)
        {
          for (outer_loop = loop; outer_loop; outer_loop = outer_loop->outer)
            {
-             if (loop_dump_stream && ! outer_loop->invalid)
-               fprintf (loop_dump_stream,
+             if (dump_file && ! outer_loop->invalid)
+               fprintf (dump_file,
                         "\nLoop at %d ignored due to unknown exit jump.\n",
                         INSN_UID (outer_loop->start));
              outer_loop->invalid = 1;
@@ -3558,7 +3564,7 @@ note_addr_stored (rtx x, rtx y ATTRIBUTE_UNUSED,
 }
 
 /* X is a value modified by an INSN that references a biv inside a loop
-   exit test (ie, X is somehow related to the value of the biv).  If X
+   exit test (i.e., X is somehow related to the value of the biv).  If X
    is a pseudo that is used more than once, then the biv is (effectively)
    used more than once.  DATA is a pointer to a loop_regs structure.  */
 
@@ -3845,7 +3851,6 @@ count_one_set (struct loop_regs *regs, rtx insn, rtx x, rtx *last_set)
       rtx dest = SET_DEST (x);
       while (GET_CODE (dest) == SUBREG
             || GET_CODE (dest) == ZERO_EXTRACT
-            || GET_CODE (dest) == SIGN_EXTRACT
             || GET_CODE (dest) == STRICT_LOW_PART)
        dest = XEXP (dest, 0);
       if (REG_P (dest))
@@ -3968,6 +3973,24 @@ rtx_equal_for_prefetch_p (rtx x, rtx y)
   if (code != GET_CODE (y))
     return 0;
 
+  if (GET_MODE (x) != GET_MODE (y))
+    return 0;
+
+  switch (code)
+    {
+    case PC:
+    case CC0:
+    case CONST_INT:
+    case CONST_DOUBLE:
+      return 0;
+
+    case LABEL_REF:
+      return XEXP (x, 0) == XEXP (y, 0);
+
+    default:
+      break;
+    }
+
   if (COMMUTATIVE_ARITH_P (x))
     {
       return ((rtx_equal_for_prefetch_p (XEXP (x, 0), XEXP (y, 0))
@@ -4027,7 +4050,7 @@ rtx_equal_for_prefetch_p (rtx x, rtx y)
             contain anything but integers and other rtx's,
             except for within LABEL_REFs and SYMBOL_REFs.  */
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
   return 1;
@@ -4113,15 +4136,15 @@ emit_prefetch_instructions (struct loop *loop)
   struct prefetch_info info[MAX_PREFETCHES];
   struct loop_ivs *ivs = LOOP_IVS (loop);
 
-  if (!HAVE_prefetch)
+  if (!HAVE_prefetch || PREFETCH_BLOCK == 0)
     return;
 
   /* Consider only loops w/o calls.  When a call is done, the loop is probably
      slow enough to read the memory.  */
   if (PREFETCH_NO_CALL && LOOP_INFO (loop)->has_call)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream, "Prefetch: ignoring loop: has call.\n");
+      if (dump_file)
+       fprintf (dump_file, "Prefetch: ignoring loop: has call.\n");
 
       return;
     }
@@ -4131,8 +4154,8 @@ emit_prefetch_instructions (struct loop *loop)
       && LOOP_INFO (loop)->n_iterations
       && LOOP_INFO (loop)->n_iterations <= PREFETCH_LOW_LOOPCNT)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Prefetch: ignoring loop: not enough iterations.\n");
       return;
     }
@@ -4157,26 +4180,26 @@ emit_prefetch_instructions (struct loop *loop)
             heuristics more conservative.  */
          if (GET_CODE (biv->add_val) != CONST_INT)
            {
-             if (loop_dump_stream)
+             if (dump_file)
                {
-                 fprintf (loop_dump_stream,
+                 fprintf (dump_file,
                    "Prefetch: ignoring biv %d: non-constant addition at insn %d:",
                           REGNO (biv->src_reg), INSN_UID (biv->insn));
-                 print_rtl (loop_dump_stream, biv->add_val);
-                 fprintf (loop_dump_stream, "\n");
+                 print_rtl (dump_file, biv->add_val);
+                 fprintf (dump_file, "\n");
                }
              break;
            }
 
          if (biv->maybe_multiple)
            {
-             if (loop_dump_stream)
+             if (dump_file)
                {
-                 fprintf (loop_dump_stream,
+                 fprintf (dump_file,
                           "Prefetch: ignoring biv %d: maybe_multiple at insn %i:",
                           REGNO (biv->src_reg), INSN_UID (biv->insn));
-                 print_rtl (loop_dump_stream, biv->add_val);
-                 fprintf (loop_dump_stream, "\n");
+                 print_rtl (dump_file, biv->add_val);
+                 fprintf (dump_file, "\n");
                }
              break;
            }
@@ -4243,8 +4266,8 @@ emit_prefetch_instructions (struct loop *loop)
 
          if (ignore_reason != NULL)
            {
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream,
+             if (dump_file)
+               fprintf (dump_file,
                         "Prefetch: ignoring giv at %d: %s.\n",
                         INSN_UID (iv->insn), ignore_reason);
              continue;
@@ -4267,8 +4290,8 @@ emit_prefetch_instructions (struct loop *loop)
            note_stores (PATTERN (iv->insn), check_store, &d);
          else
            {
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream, "Prefetch: Ignoring giv at %d: %s\n",
+             if (dump_file)
+               fprintf (dump_file, "Prefetch: Ignoring giv at %d: %s\n",
                         INSN_UID (iv->insn), "in conditional code.");
              continue;
            }
@@ -4322,8 +4345,8 @@ emit_prefetch_instructions (struct loop *loop)
              num_prefetches++;
              if (num_prefetches >= MAX_PREFETCHES)
                {
-                 if (loop_dump_stream)
-                   fprintf (loop_dump_stream,
+                 if (dump_file)
+                   fprintf (dump_file,
                             "Maximal number of prefetches exceeded.\n");
                  return;
                }
@@ -4360,8 +4383,8 @@ emit_prefetch_instructions (struct loop *loop)
        else
          {
            info[i].prefetch_in_loop = 0, info[i].prefetch_before_loop = 0;
-           if (loop_dump_stream)
-             fprintf (loop_dump_stream,
+           if (dump_file)
+             fprintf (dump_file,
                  "Prefetch: ignoring giv at %d: %d%% density is too low.\n",
                       INSN_UID (info[i].giv->insn), density);
          }
@@ -4385,8 +4408,8 @@ emit_prefetch_instructions (struct loop *loop)
     {
       if ((ahead = SIMULTANEOUS_PREFETCHES / num_real_prefetches) == 0)
        {
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream,
+         if (dump_file)
+           fprintf (dump_file,
                     "Prefetch: ignoring prefetches within loop: ahead is zero; %d < %d\n",
                     SIMULTANEOUS_PREFETCHES, num_real_prefetches);
          num_real_prefetches = 0, num_real_write_prefetches = 0;
@@ -4415,27 +4438,27 @@ emit_prefetch_instructions (struct loop *loop)
            num_write_prefetches_before += n;
        }
 
-      if (loop_dump_stream)
+      if (dump_file)
        {
          if (info[i].prefetch_in_loop == 0
              && info[i].prefetch_before_loop == 0)
            continue;
-         fprintf (loop_dump_stream, "Prefetch insn: %d",
+         fprintf (dump_file, "Prefetch insn: %d",
                   INSN_UID (info[i].giv->insn));
-         fprintf (loop_dump_stream,
+         fprintf (dump_file,
                   "; in loop: %d; before: %d; %s\n",
                   info[i].prefetch_in_loop,
                   info[i].prefetch_before_loop,
                   info[i].write ? "read/write" : "read only");
-         fprintf (loop_dump_stream,
+         fprintf (dump_file,
                   " density: %d%%; bytes_accessed: %u; total_bytes: %u\n",
                   (int) (info[i].bytes_accessed * 100 / info[i].stride),
                   info[i].bytes_accessed, info[i].total_bytes);
-         fprintf (loop_dump_stream, " index: " HOST_WIDE_INT_PRINT_DEC
+         fprintf (dump_file, " index: " HOST_WIDE_INT_PRINT_DEC
                   "; stride: " HOST_WIDE_INT_PRINT_DEC "; address: ",
                   info[i].index, info[i].stride);
-         print_rtl (loop_dump_stream, info[i].base_address);
-         fprintf (loop_dump_stream, "\n");
+         print_rtl (dump_file, info[i].base_address);
+         fprintf (dump_file, "\n");
        }
     }
 
@@ -4444,11 +4467,11 @@ emit_prefetch_instructions (struct loop *loop)
       /* Record that this loop uses prefetch instructions.  */
       LOOP_INFO (loop)->has_prefetch = 1;
 
-      if (loop_dump_stream)
+      if (dump_file)
        {
-         fprintf (loop_dump_stream, "Real prefetches needed within loop: %d (write: %d)\n",
+         fprintf (dump_file, "Real prefetches needed within loop: %d (write: %d)\n",
                   num_real_prefetches, num_real_write_prefetches);
-         fprintf (loop_dump_stream, "Real prefetches needed before loop: %d (write: %d)\n",
+         fprintf (dump_file, "Real prefetches needed before loop: %d (write: %d)\n",
                   num_prefetches_before, num_write_prefetches_before);
        }
     }
@@ -4644,12 +4667,18 @@ for_each_insn_in_loop (struct loop *loop, loop_insn_callback fncall)
   int not_every_iteration = 0;
   int maybe_multiple = 0;
   int past_loop_latch = 0;
+  bool exit_test_is_entry = false;
   rtx p;
 
-  /* If loop_scan_start points to the loop exit test, we have to be wary of
-     subversive use of gotos inside expression statements.  */
+  /* If loop_scan_start points to the loop exit test, the loop body
+     cannot be counted on running on every iteration, and we have to
+     be wary of subversive use of gotos inside expression
+     statements.  */
   if (prev_nonnote_insn (loop->scan_start) != prev_nonnote_insn (loop->start))
-    maybe_multiple = back_branch_in_range_p (loop, loop->scan_start);
+    {
+      exit_test_is_entry = true;
+      maybe_multiple = back_branch_in_range_p (loop, loop->scan_start);
+    }
 
   /* Scan through loop and update NOT_EVERY_ITERATION and MAYBE_MULTIPLE.  */
   for (p = next_insn_in_loop (loop, loop->scan_start);
@@ -4707,10 +4736,12 @@ for_each_insn_in_loop (struct loop *loop, loop_insn_callback fncall)
          beginning, don't set not_every_iteration for that.
          This can be any kind of jump, since we want to know if insns
          will be executed if the loop is executed.  */
-         && !(JUMP_LABEL (p) == loop->top
-              && ((NEXT_INSN (NEXT_INSN (p)) == loop->end
-                   && any_uncondjump_p (p))
-                  || (NEXT_INSN (p) == loop->end && any_condjump_p (p)))))
+         && (exit_test_is_entry
+             || !(JUMP_LABEL (p) == loop->top
+                  && ((NEXT_INSN (NEXT_INSN (p)) == loop->end
+                       && any_uncondjump_p (p))
+                      || (NEXT_INSN (p) == loop->end
+                          && any_condjump_p (p))))))
        {
          rtx label = 0;
 
@@ -4780,8 +4811,8 @@ loop_bivs_find (struct loop *loop)
             move.  So leave it alone.  */
          || ! bl->incremented)
        {
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream, "Biv %d: discarded, %s\n",
+         if (dump_file)
+           fprintf (dump_file, "Biv %d: discarded, %s\n",
                     bl->regno,
                     (REG_IV_TYPE (ivs, bl->regno) != BASIC_INDUCT
                      ? "not induction variable"
@@ -4795,8 +4826,8 @@ loop_bivs_find (struct loop *loop)
        {
          backbl = &bl->next;
 
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream, "Biv %d: verified\n", bl->regno);
+         if (dump_file)
+           fprintf (dump_file, "Biv %d: verified\n", bl->regno);
        }
     }
 }
@@ -4885,8 +4916,8 @@ loop_bivs_check (struct loop *loop)
       else
        src = SET_SRC (bl->init_set);
 
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Biv %d: initialized at insn %d: initial value ",
                 bl->regno, INSN_UID (bl->init_insn));
 
@@ -4898,16 +4929,16 @@ loop_bivs_check (struct loop *loop)
        {
          bl->initial_value = src;
 
-         if (loop_dump_stream)
+         if (dump_file)
            {
-             print_simple_rtl (loop_dump_stream, src);
-             fputc ('\n', loop_dump_stream);
+             print_simple_rtl (dump_file, src);
+             fputc ('\n', dump_file);
            }
        }
       /* If we can't make it a giv,
         let biv keep initial value of "itself".  */
-      else if (loop_dump_stream)
-       fprintf (loop_dump_stream, "is complex\n");
+      else if (dump_file)
+       fprintf (dump_file, "is complex\n");
     }
 }
 
@@ -4953,10 +4984,9 @@ fold_rtx_mult_add (rtx mult1, rtx mult2, rtx add1, enum machine_mode mode)
 
   /* The modes must all be the same.  This should always be true.  For now,
      check to make sure.  */
-  if ((GET_MODE (mult1) != mode && GET_MODE (mult1) != VOIDmode)
-      || (GET_MODE (mult2) != mode && GET_MODE (mult2) != VOIDmode)
-      || (GET_MODE (add1) != mode && GET_MODE (add1) != VOIDmode))
-    abort ();
+  gcc_assert (GET_MODE (mult1) == mode || GET_MODE (mult1) == VOIDmode);
+  gcc_assert (GET_MODE (mult2) == mode || GET_MODE (mult2) == VOIDmode);
+  gcc_assert (GET_MODE (add1) == mode || GET_MODE (add1) == VOIDmode);
 
   /* Ensure that if at least one of mult1/mult2 are constant, then mult2
      will be a constant.  */
@@ -5054,7 +5084,7 @@ reg_dead_after_loop (const struct loop *loop, rtx reg)
   /* HACK: Must also search the loop fall through exit, create a label_ref
      here which points to the loop->end, and append the loop_number_exit_labels
      list to it.  */
-  label = gen_rtx_LABEL_REF (VOIDmode, loop->end);
+  label = gen_rtx_LABEL_REF (Pmode, loop->end);
   LABEL_NEXTREF (label) = loop->exit_labels;
 
   for (; label; label = LABEL_NEXTREF (label))
@@ -5122,8 +5152,8 @@ final_biv_value (const struct loop *loop, struct iv_class *bl)
      no other loop exits, so we can return any value.  */
   if (bl->reversed)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Final biv value for %d, reversed biv.\n", bl->regno);
 
       return const0_rtx;
@@ -5152,8 +5182,8 @@ final_biv_value (const struct loop *loop, struct iv_class *bl)
          loop_iv_add_mult_sink (loop, increment, GEN_INT (n_iterations),
                                 bl->initial_value, tem);
 
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream,
+         if (dump_file)
+           fprintf (dump_file,
                     "Final biv value for %d, calculated.\n", bl->regno);
 
          return tem;
@@ -5163,8 +5193,8 @@ final_biv_value (const struct loop *loop, struct iv_class *bl)
   /* Check to see if the biv is dead at all loop exits.  */
   if (reg_dead_after_loop (loop, bl->biv->src_reg))
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Final biv value for %d, biv dead after loop exit.\n",
                 bl->regno);
 
@@ -5190,8 +5220,8 @@ loop_biv_eliminable_p (struct loop *loop, struct iv_class *bl,
 #ifdef HAVE_decrement_and_branch_until_zero
   if (bl->nonneg)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Cannot eliminate nonneg biv %d.\n", bl->regno);
       return 0;
     }
@@ -5212,12 +5242,12 @@ loop_biv_eliminable_p (struct loop *loop, struct iv_class *bl,
       || (bl->final_value = final_biv_value (loop, bl)))
     return maybe_eliminate_biv (loop, bl, 0, threshold,        insn_count);
 
-  if (loop_dump_stream)
+  if (dump_file)
     {
-      fprintf (loop_dump_stream,
+      fprintf (dump_file,
               "Cannot eliminate biv %d.\n",
               bl->regno);
-      fprintf (loop_dump_stream,
+      fprintf (dump_file,
               "First use: insn %d, last use: insn %d.\n",
               REGNO_FIRST_UID (bl->regno),
               REGNO_LAST_UID (bl->regno));
@@ -5459,9 +5489,64 @@ loop_givs_rescan (struct loop *loop, struct iv_class *bl, rtx *reg_map)
        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.  */
-       validate_change (v->insn, v->location, v->new_reg, 0);
+       {
+         /* Store reduced reg as the address in the memref where we found
+            this giv.  */
+         if (validate_change_maybe_volatile (v->insn, v->location,
+                                             v->new_reg))
+           /* Yay, it worked!  */;
+         /* Not replaceable; emit an insn to set the original
+            giv reg from the reduced giv.  */
+         else if (REG_P (*v->location))
+           {
+             rtx tem;
+             start_sequence ();
+             tem = force_operand (v->new_reg, *v->location);
+             if (tem != *v->location)
+               emit_move_insn (*v->location, tem);
+             tem = get_insns ();
+             end_sequence ();
+             loop_insn_emit_before (loop, 0, v->insn, tem);
+           }
+         else if (GET_CODE (*v->location) == PLUS
+                  && REG_P (XEXP (*v->location, 0))
+                  && CONSTANT_P (XEXP (*v->location, 1)))
+           {
+             rtx tem;
+             start_sequence ();
+             tem = expand_simple_binop (GET_MODE (*v->location), MINUS,
+                                        v->new_reg, XEXP (*v->location, 1),
+                                        NULL_RTX, 0, OPTAB_LIB_WIDEN);
+             emit_move_insn (XEXP (*v->location, 0), tem);
+             tem = get_insns ();
+             end_sequence ();
+             loop_insn_emit_before (loop, 0, v->insn, tem);
+           }
+         else
+           {
+             /* If it wasn't a reg, create a pseudo and use that.  */
+             rtx reg, seq;
+             start_sequence ();
+             reg = force_reg (v->mode, *v->location);
+             if (validate_change_maybe_volatile (v->insn, v->location, reg))
+               {
+                 seq = get_insns ();
+                 end_sequence ();
+                 loop_insn_emit_before (loop, 0, v->insn, seq);
+               }
+             else
+               {
+                 end_sequence ();
+                 if (dump_file)
+                   fprintf (dump_file,
+                            "unable to reduce iv in insn %d\n",
+                            INSN_UID (v->insn));
+                 bl->all_reduced = 0;
+                 v->ignore = 1;
+                 continue;
+               }
+           }
+       }
       else if (v->replaceable)
        {
          reg_map[REGNO (v->dest_reg)] = v->new_reg;
@@ -5500,12 +5585,12 @@ loop_givs_rescan (struct loop *loop, struct iv_class *bl, rtx *reg_map)
                                gen_load_of_final_value (v->dest_reg,
                                                         v->final_value));
 
-      if (loop_dump_stream)
+      if (dump_file)
        {
-         fprintf (loop_dump_stream, "giv at %d reduced to ",
+         fprintf (dump_file, "giv at %d reduced to ",
                   INSN_UID (v->insn));
-         print_simple_rtl (loop_dump_stream, v->new_reg);
-         fprintf (loop_dump_stream, "\n");
+         print_simple_rtl (dump_file, v->new_reg);
+         fprintf (dump_file, "\n");
        }
     }
 }
@@ -5741,8 +5826,8 @@ loop_iterations (struct loop *loop)
      the last loop insn is a jump to the top of the loop.  */
   if (!JUMP_P (last_loop_insn))
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Loop iterations: No final conditional branch found.\n");
       return 0;
     }
@@ -5751,8 +5836,8 @@ loop_iterations (struct loop *loop)
      we cannot (easily) determine the iteration count.  */
   if (LABEL_NUSES (JUMP_LABEL (last_loop_insn)) > 1)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Loop iterations: Loop has multiple back edges.\n");
       return 0;
     }
@@ -5764,8 +5849,8 @@ loop_iterations (struct loop *loop)
   comparison = get_condition_for_loop (loop, last_loop_insn);
   if (comparison == 0)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Loop iterations: No final comparison found.\n");
       return 0;
     }
@@ -5779,8 +5864,8 @@ loop_iterations (struct loop *loop)
 
   if (!REG_P (iteration_var))
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Loop iterations: Comparison not against register.\n");
       return 0;
     }
@@ -5791,9 +5876,8 @@ loop_iterations (struct loop *loop)
      will propagate a new pseudo into the old iteration register but
      this will be marked by having the REG_USERVAR_P bit set.  */
 
-  if ((unsigned) REGNO (iteration_var) >= ivs->n_regs
-      && ! REG_USERVAR_P (iteration_var))
-    abort ();
+  gcc_assert ((unsigned) REGNO (iteration_var) < ivs->n_regs
+             || REG_USERVAR_P (iteration_var));
 
   /* Determine the initial value of the iteration variable, and the amount
      that it is incremented each loop.  Use the tables constructed by
@@ -5811,8 +5895,8 @@ loop_iterations (struct loop *loop)
      reg_iv_type entry for it.  */
   if ((unsigned) REGNO (iteration_var) >= ivs->n_regs)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Loop iterations: No reg_iv_type entry for iteration var.\n");
       return 0;
     }
@@ -5823,15 +5907,15 @@ loop_iterations (struct loop *loop)
   else if ((GET_MODE_BITSIZE (GET_MODE (iteration_var))
            > HOST_BITS_PER_WIDE_INT))
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Loop iterations: Iteration var rejected because mode too large.\n");
       return 0;
     }
   else if (GET_MODE_CLASS (GET_MODE (iteration_var)) != MODE_INT)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Loop iterations: Iteration var not an integer.\n");
       return 0;
     }
@@ -5850,16 +5934,15 @@ loop_iterations (struct loop *loop)
 
   if (REG_IV_TYPE (ivs, REGNO (iteration_var)) == BASIC_INDUCT)
     {
-      if (REGNO (iteration_var) >= ivs->n_regs)
-       abort ();
+      gcc_assert (REGNO (iteration_var) < ivs->n_regs);
 
       /* Grab initial value, only useful if it is a constant.  */
       bl = REG_IV_CLASS (ivs, REGNO (iteration_var));
       initial_value = bl->initial_value;
       if (!bl->biv->always_executed || bl->biv->maybe_multiple)
        {
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream,
+         if (dump_file)
+           fprintf (dump_file,
                     "Loop iterations: Basic induction var not set once in each iteration.\n");
          return 0;
        }
@@ -5872,13 +5955,12 @@ loop_iterations (struct loop *loop)
       struct induction *v = REG_IV_INFO (ivs, REGNO (iteration_var));
       rtx biv_initial_value;
 
-      if (REGNO (v->src_reg) >= ivs->n_regs)
-       abort ();
+      gcc_assert (REGNO (v->src_reg) < ivs->n_regs);
 
       if (!v->always_executed || v->maybe_multiple)
        {
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream,
+         if (dump_file)
+           fprintf (dump_file,
                     "Loop iterations: General induction var not set once in each iteration.\n");
          return 0;
        }
@@ -5907,8 +5989,8 @@ loop_iterations (struct loop *loop)
                {
                  if (REG_P (biv_inc->add_val))
                    {
-                     if (loop_dump_stream)
-                       fprintf (loop_dump_stream,
+                     if (dump_file)
+                       fprintf (dump_file,
                                 "Loop iterations: Basic induction var add_val is REG %d.\n",
                                 REGNO (biv_inc->add_val));
                        return 0;
@@ -5922,8 +6004,8 @@ loop_iterations (struct loop *loop)
                }
            }
        }
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Loop iterations: Giv iterator, initial value bias %ld.\n",
                 (long) offset);
 
@@ -5937,8 +6019,8 @@ loop_iterations (struct loop *loop)
     }
   else
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Loop iterations: Not basic or general induction var.\n");
       return 0;
     }
@@ -5980,7 +6062,7 @@ loop_iterations (struct loop *loop)
       compare_dir = 0;
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   /* If the comparison value is an invariant register, then try to find
@@ -6083,8 +6165,8 @@ loop_iterations (struct loop *loop)
 
   if (increment == 0)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Loop iterations: Increment value can't be calculated.\n");
       return 0;
     }
@@ -6099,12 +6181,12 @@ loop_iterations (struct loop *loop)
 
       if (GET_CODE (increment) != CONST_INT)
        {
-         if (loop_dump_stream)
+         if (dump_file)
            {
-             fprintf (loop_dump_stream,
+             fprintf (dump_file,
                       "Loop iterations: Increment value not constant ");
-             print_simple_rtl (loop_dump_stream, increment);
-             fprintf (loop_dump_stream, ".\n");
+             print_simple_rtl (dump_file, increment);
+             fprintf (dump_file, ".\n");
            }
          return 0;
        }
@@ -6113,23 +6195,23 @@ loop_iterations (struct loop *loop)
 
   if (GET_CODE (initial_value) != CONST_INT)
     {
-      if (loop_dump_stream)
+      if (dump_file)
        {
-         fprintf (loop_dump_stream,
+         fprintf (dump_file,
                   "Loop iterations: Initial value not constant ");
-         print_simple_rtl (loop_dump_stream, initial_value);
-         fprintf (loop_dump_stream, ".\n");
+         print_simple_rtl (dump_file, initial_value);
+         fprintf (dump_file, ".\n");
        }
       return 0;
     }
   else if (GET_CODE (final_value) != CONST_INT)
     {
-      if (loop_dump_stream)
+      if (dump_file)
        {
-         fprintf (loop_dump_stream,
+         fprintf (dump_file,
                   "Loop iterations: Final value not constant ");
-         print_simple_rtl (loop_dump_stream, final_value);
-         fprintf (loop_dump_stream, ".\n");
+         print_simple_rtl (dump_file, final_value);
+         fprintf (dump_file, ".\n");
        }
       return 0;
     }
@@ -6137,8 +6219,8 @@ loop_iterations (struct loop *loop)
     {
       rtx inc_once;
 
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream, "Loop iterations: EQ comparison loop.\n");
+      if (dump_file)
+       fprintf (dump_file, "Loop iterations: EQ comparison loop.\n");
 
       inc_once = gen_int_mode (INTVAL (initial_value) + INTVAL (increment),
                               GET_MODE (iteration_var));
@@ -6222,8 +6304,8 @@ loop_iterations (struct loop *loop)
     ;
   else
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream, "Loop iterations: Not normal loop.\n");
+      if (dump_file)
+       fprintf (dump_file, "Loop iterations: Not normal loop.\n");
       return 0;
     }
 
@@ -6232,18 +6314,17 @@ loop_iterations (struct loop *loop)
      unsigned, because they can be as large as 2^n - 1.  */
 
   inc = INTVAL (increment);
+  gcc_assert (inc);
   if (inc > 0)
     {
       abs_diff = INTVAL (final_value) - INTVAL (initial_value);
       abs_inc = inc;
     }
-  else if (inc < 0)
+  else
     {
       abs_diff = INTVAL (initial_value) - INTVAL (final_value);
       abs_inc = -inc;
     }
-  else
-    abort ();
 
   /* Given that iteration_var is going to iterate over its own mode,
      not HOST_WIDE_INT, disregard higher bits that might have come
@@ -6300,7 +6381,7 @@ strength_reduce (struct loop *loop, int flags)
   addr_placeholder = gen_reg_rtx (Pmode);
 
   ivs->n_regs = max_reg_before_loop;
-  ivs->regs = xcalloc (ivs->n_regs, sizeof (struct iv));
+  ivs->regs = XCNEWVEC (struct iv, ivs->n_regs);
 
   /* Find all BIVs in loop.  */
   loop_bivs_find (loop);
@@ -6349,7 +6430,7 @@ strength_reduce (struct loop *loop, int flags)
      Some givs might have been made from biv increments, so look at
      ivs->reg_iv_type for a suitable size.  */
   reg_map_size = ivs->n_regs;
-  reg_map = xcalloc (reg_map_size, sizeof (rtx));
+  reg_map = XCNEWVEC (rtx, reg_map_size);
 
   /* Examine each iv class for feasibility of strength reduction/induction
      variable elimination.  */
@@ -6396,14 +6477,25 @@ strength_reduce (struct loop *loop, int flags)
          if (v->lifetime * threshold * benefit < insn_count
              && ! bl->reversed)
            {
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream,
+             if (dump_file)
+               fprintf (dump_file,
                         "giv of insn %d not worth while, %d vs %d.\n",
                         INSN_UID (v->insn),
                         v->lifetime * threshold * benefit, insn_count);
              v->ignore = 1;
              bl->all_reduced = 0;
            }
+         else if (!v->always_computable
+                  && (may_trap_or_fault_p (v->add_val)
+                      || may_trap_or_fault_p (v->mult_val)))
+           {
+             if (dump_file)
+               fprintf (dump_file,
+                        "giv of insn %d: not always computable.\n",
+                        INSN_UID (v->insn));
+             v->ignore = 1;
+             bl->all_reduced = 0;
+           }
          else
            {
              /* Check that we can increment the reduced giv without a
@@ -6413,8 +6505,8 @@ strength_reduce (struct loop *loop, int flags)
                if (tv->mult_val == const1_rtx
                    && ! product_cheap_p (tv->add_val, v->mult_val))
                  {
-                   if (loop_dump_stream)
-                     fprintf (loop_dump_stream,
+                   if (dump_file)
+                     fprintf (dump_file,
                               "giv of insn %d: would need a multiply.\n",
                               INSN_UID (v->insn));
                    v->ignore = 1;
@@ -6497,8 +6589,8 @@ strength_reduce (struct loop *loop, int flags)
                                      gen_load_of_final_value (bl->biv->dest_reg,
                                                               bl->final_value));
 
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream, "Reg %d: biv eliminated\n",
+         if (dump_file)
+           fprintf (dump_file, "Reg %d: biv eliminated\n",
                     bl->regno);
        }
       /* See above note wrt final_value.  But since we couldn't eliminate
@@ -6519,8 +6611,8 @@ strength_reduce (struct loop *loop, int flags)
        INSN_CODE (p) = -1;
       }
 
-  if (loop_dump_stream)
-    fprintf (loop_dump_stream, "\n");
+  if (dump_file)
+    fprintf (dump_file, "\n");
 
   loop_ivs_free (loop);
   if (reg_map)
@@ -6556,7 +6648,7 @@ check_insn_for_bivs (struct loop *loop, rtx p, int not_every_iteration,
              /* It is a possible basic induction variable.
                 Create and initialize an induction structure for it.  */
 
-             struct induction *v = xmalloc (sizeof (struct induction));
+             struct induction *v = XNEW (struct induction);
 
              record_biv (loop, v, p, dest_reg, inc_val, mult_val, location,
                          not_every_iteration, maybe_multiple);
@@ -6619,7 +6711,7 @@ check_insn_for_givs (struct loop *loop, rtx p, int not_every_iteration,
                                             &add_val, &mult_val, &ext_val,
                                             &last_consec_insn))))
        {
-         struct induction *v = xmalloc (sizeof (struct induction));
+         struct induction *v = XNEW (struct induction);
 
          /* If this is a library call, increase benefit.  */
          if (find_reg_note (p, REG_RETVAL, NULL_RTX))
@@ -6672,7 +6764,7 @@ valid_initial_value_p (rtx x, rtx insn, int call_seen, rtx loop_start)
      some machines, don't use any hard registers at all.  */
   if (REGNO (x) < FIRST_PSEUDO_REGISTER
       && (SMALL_REGISTER_CLASSES
-         || (call_used_regs[REGNO (x)] && call_seen)))
+         || (call_seen && call_used_regs[REGNO (x)])))
     return 0;
 
   /* Don't use registers that have been clobbered before the start of the
@@ -6735,7 +6827,7 @@ find_mem_givs (const struct loop *loop, rtx x, rtx insn,
                                   GET_MODE (x)))
          {
            /* Found one; record it.  */
-           struct induction *v = xmalloc (sizeof (struct induction));
+           struct induction *v = XNEW (struct induction);
 
            record_giv (loop, v, insn, src_reg, addr_placeholder, mult_val,
                        add_val, ext_val, benefit, DEST_ADDR,
@@ -6808,7 +6900,7 @@ record_biv (struct loop *loop, struct induction *v, rtx insn, rtx dest_reg,
     {
       /* Create and initialize new iv_class.  */
 
-      bl = xmalloc (sizeof (struct iv_class));
+      bl = XNEW (struct iv_class);
 
       bl->regno = REGNO (dest_reg);
       bl->biv = 0;
@@ -6855,8 +6947,8 @@ record_biv (struct loop *loop, struct induction *v, rtx insn, rtx dest_reg,
   if (mult_val == const1_rtx)
     bl->incremented = 1;
 
-  if (loop_dump_stream)
-    loop_biv_dump (v, loop_dump_stream, 0);
+  if (dump_file)
+    loop_biv_dump (v, dump_file, 0);
 }
 \f
 /* Fill in the data about one giv.
@@ -6953,19 +7045,15 @@ record_giv (const struct loop *loop, struct induction *v, rtx insn,
   /* Add the giv to the class of givs computed from one biv.  */
 
   bl = REG_IV_CLASS (ivs, REGNO (src_reg));
-  if (bl)
-    {
-      v->next_iv = bl->giv;
-      bl->giv = v;
-      /* Don't count DEST_ADDR.  This is supposed to count the number of
-        insns that calculate givs.  */
-      if (type == DEST_REG)
-       bl->giv_count++;
-      bl->total_benefit += benefit;
-    }
-  else
-    /* Fatal error, biv missing for this giv?  */
-    abort ();
+  gcc_assert (bl);
+  v->next_iv = bl->giv;
+  bl->giv = v;
+  
+  /* Don't count DEST_ADDR.  This is supposed to count the number of
+     insns that calculate givs.  */
+  if (type == DEST_REG)
+    bl->giv_count++;
+  bl->total_benefit += benefit;
 
   if (type == DEST_ADDR)
     {
@@ -7067,8 +7155,8 @@ record_giv (const struct loop *loop, struct induction *v, rtx insn,
       }
   }
 
-  if (loop_dump_stream)
-    loop_giv_dump (v, loop_dump_stream, 0);
+  if (dump_file)
+    loop_giv_dump (v, dump_file, 0);
 }
 
 /* Try to calculate the final value of the giv, the value it will have at
@@ -7093,8 +7181,8 @@ final_giv_value (const struct loop *loop, struct induction *v)
      and there are no other loop exits, so we can return any value.  */
   if (bl->reversed)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Final giv value for %d, depends on reversed biv\n",
                 REGNO (v->dest_reg));
       return const0_rtx;
@@ -7170,8 +7258,8 @@ final_giv_value (const struct loop *loop, struct induction *v)
          /* Now calculate the giv's final value.  */
          loop_iv_add_mult_sink (loop, tem, v->mult_val, v->add_val, tem);
 
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream,
+         if (dump_file)
+           fprintf (dump_file,
                     "Final giv value for %d, calc from biv's value.\n",
                     REGNO (v->dest_reg));
 
@@ -7180,14 +7268,13 @@ final_giv_value (const struct loop *loop, struct induction *v)
     }
 
   /* Replaceable giv's should never reach here.  */
-  if (v->replaceable)
-    abort ();
+  gcc_assert (!v->replaceable);
 
   /* Check to see if the biv is dead at all loop exits.  */
   if (reg_dead_after_loop (loop, v->dest_reg))
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
+      if (dump_file)
+       fprintf (dump_file,
                 "Final giv value for %d, giv dead after loop exit.\n",
                 REGNO (v->dest_reg));
 
@@ -7320,8 +7407,8 @@ check_final_value (const struct loop *loop, struct induction *v)
                  v->replaceable = 0;
                  v->not_replaceable = 1;
 
-                 if (loop_dump_stream)
-                   fprintf (loop_dump_stream,
+                 if (dump_file)
+                   fprintf (dump_file,
                             "Found branch outside giv lifetime.\n");
 
                  break;
@@ -7334,8 +7421,8 @@ check_final_value (const struct loop *loop, struct induction *v)
        v->final_value = final_value;
     }
 
-  if (loop_dump_stream && v->replaceable)
-    fprintf (loop_dump_stream, "Insn %d: giv reg %d final_value replaceable\n",
+  if (dump_file && v->replaceable)
+    fprintf (dump_file, "Insn %d: giv reg %d final_value replaceable\n",
             INSN_UID (v->insn), REGNO (v->dest_reg));
 }
 \f
@@ -7591,9 +7678,8 @@ basic_induction_var (const struct loop *loop, rtx x, enum machine_mode mode,
                                        dest_reg, insn,
                                        inc_val, mult_val, location);
 
-         while (GET_CODE (dest) == SIGN_EXTRACT
+         while (GET_CODE (dest) == SUBREG
                 || GET_CODE (dest) == ZERO_EXTRACT
-                || GET_CODE (dest) == SUBREG
                 || GET_CODE (dest) == STRICT_LOW_PART)
            dest = XEXP (dest, 0);
          if (dest == x)
@@ -7611,9 +7697,9 @@ basic_induction_var (const struct loop *loop, rtx x, enum machine_mode mode,
     case CONST_INT:
     case SYMBOL_REF:
     case CONST:
-      /* convert_modes aborts if we try to convert to or from CCmode, so just
+      /* convert_modes dies if we try to convert to or from CCmode, so just
          exclude that case.  It is very unlikely that a condition code value
-        would be a useful iterator anyways.  convert_modes aborts if we try to
+        would be a useful iterator anyways.  convert_modes dies if we try to
         convert a float mode to non-float or vice versa too.  */
       if (loop->level == 1
          && GET_MODE_CLASS (mode) == GET_MODE_CLASS (GET_MODE (dest_reg))
@@ -7746,7 +7832,7 @@ general_induction_var (const struct loop *loop, rtx x, rtx *src_reg,
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   /* Remove any enclosing USE from ADD_VAL and MULT_VAL (there will be
@@ -7865,7 +7951,7 @@ simplify_giv_expr (const struct loop *loop, rtx x, rtx *ext_val, int *benefit)
                                 ext_val, benefit);
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
 
       /* Each argument must be either REG, PLUS, or MULT.  Convert REG to
@@ -8006,7 +8092,7 @@ simplify_giv_expr (const struct loop *loop, rtx x, rtx *ext_val, int *benefit)
                                    ext_val, benefit);
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
     case ASHIFT:
@@ -8606,192 +8692,261 @@ combine_givs_p (struct induction *g1, struct induction *g2)
   return NULL_RTX;
 }
 \f
-/* Check each extension dependent giv in this class to see if its
-   root biv is safe from wrapping in the interior mode, which would
-   make the giv illegal.  */
+/* See if BL is monotonic and has a constant per-iteration increment.
+   Return the increment if so, otherwise return 0.  */
 
-static void
-check_ext_dependent_givs (const struct loop *loop, struct iv_class *bl)
+static HOST_WIDE_INT
+get_monotonic_increment (struct iv_class *bl)
 {
-  struct loop_info *loop_info = LOOP_INFO (loop);
-  int ze_ok = 0, se_ok = 0, info_ok = 0;
-  enum machine_mode biv_mode = GET_MODE (bl->biv->src_reg);
-  HOST_WIDE_INT start_val;
-  unsigned HOST_WIDE_INT u_end_val = 0;
-  unsigned HOST_WIDE_INT u_start_val = 0;
-  rtx incr = pc_rtx;
   struct induction *v;
+  rtx incr;
+
+  /* Get the total increment and check that it is constant.  */
+  incr = biv_total_increment (bl);
+  if (incr == 0 || GET_CODE (incr) != CONST_INT)
+    return 0;
+
+  for (v = bl->biv; v != 0; v = v->next_iv)
+    {
+      if (GET_CODE (v->add_val) != CONST_INT)
+       return 0;
+
+      if (INTVAL (v->add_val) < 0 && INTVAL (incr) >= 0)
+       return 0;
+
+      if (INTVAL (v->add_val) > 0 && INTVAL (incr) <= 0)
+       return 0;
+    }
+  return INTVAL (incr);
+}
+
+
+/* Subroutine of biv_fits_mode_p.  Return true if biv BL, when biased by
+   BIAS, will never exceed the unsigned range of MODE.  LOOP is the loop
+   to which the biv belongs and INCR is its per-iteration increment.  */
+
+static bool
+biased_biv_fits_mode_p (const struct loop *loop, struct iv_class *bl,
+                       HOST_WIDE_INT incr, enum machine_mode mode,
+                       unsigned HOST_WIDE_INT bias)
+{
+  unsigned HOST_WIDE_INT initial, maximum, span, delta;
+
+  /* We need to be able to manipulate MODE-size constants.  */
+  if (HOST_BITS_PER_WIDE_INT < GET_MODE_BITSIZE (mode))
+    return false;
+
+  /* The number of loop iterations must be constant.  */
+  if (LOOP_INFO (loop)->n_iterations == 0)
+    return false;
+
+  /* So must the biv's initial value.  */
+  if (bl->initial_value == 0 || GET_CODE (bl->initial_value) != CONST_INT)
+    return false;
+
+  initial = bias + INTVAL (bl->initial_value);
+  maximum = GET_MODE_MASK (mode);
+
+  /* Make sure that the initial value is within range.  */
+  if (initial > maximum)
+    return false;
+
+  /* Set up DELTA and SPAN such that the number of iterations * DELTA
+     (calculated to arbitrary precision) must be <= SPAN.  */
+  if (incr < 0)
+    {
+      delta = -incr;
+      span = initial;
+    }
+  else
+    {
+      delta = incr;
+      /* Handle the special case in which MAXIMUM is the largest
+        unsigned HOST_WIDE_INT and INITIAL is 0.  */
+      if (maximum + 1 == initial)
+       span = LOOP_INFO (loop)->n_iterations * delta;
+      else
+       span = maximum + 1 - initial;
+    }
+  return (span / LOOP_INFO (loop)->n_iterations >= delta);
+}
+
+
+/* Return true if biv BL will never exceed the bounds of MODE.  LOOP is
+   the loop to which BL belongs and INCR is its per-iteration increment.
+   UNSIGNEDP is true if the biv should be treated as unsigned.  */
+
+static bool
+biv_fits_mode_p (const struct loop *loop, struct iv_class *bl,
+                HOST_WIDE_INT incr, enum machine_mode mode, bool unsignedp)
+{
+  struct loop_info *loop_info;
+  unsigned HOST_WIDE_INT bias;
+
+  /* A biv's value will always be limited to its natural mode.
+     Larger modes will observe the same wrap-around.  */
+  if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (bl->biv->src_reg)))
+    mode = GET_MODE (bl->biv->src_reg);
+
+  loop_info = LOOP_INFO (loop);
 
-  /* Make sure the iteration data is available.  We must have
-     constants in order to be certain of no overflow.  */
-  if (loop_info->n_iterations > 0
-      && bl->initial_value
-      && GET_CODE (bl->initial_value) == CONST_INT
-      && (incr = biv_total_increment (bl))
-      && GET_CODE (incr) == CONST_INT
-      /* Make sure the host can represent the arithmetic.  */
-      && HOST_BITS_PER_WIDE_INT >= GET_MODE_BITSIZE (biv_mode))
-    {
-      unsigned HOST_WIDE_INT abs_incr, total_incr;
-      HOST_WIDE_INT s_end_val;
-      int neg_incr;
-
-      info_ok = 1;
-      start_val = INTVAL (bl->initial_value);
-      u_start_val = start_val;
-
-      neg_incr = 0, abs_incr = INTVAL (incr);
-      if (INTVAL (incr) < 0)
-       neg_incr = 1, abs_incr = -abs_incr;
-      total_incr = abs_incr * loop_info->n_iterations;
-
-      /* Check for host arithmetic overflow.  */
-      if (total_incr / loop_info->n_iterations == abs_incr)
+  bias = (unsignedp ? 0 : (GET_MODE_MASK (mode) >> 1) + 1);
+  if (biased_biv_fits_mode_p (loop, bl, incr, mode, bias))
+    return true;
+
+  if (mode == GET_MODE (bl->biv->src_reg)
+      && bl->biv->src_reg == loop_info->iteration_var
+      && loop_info->comparison_value
+      && loop_invariant_p (loop, loop_info->comparison_value))
+    {
+      /* If the increment is +1, and the exit test is a <, the BIV
+         cannot overflow.  (For <=, we have the problematic case that
+         the comparison value might be the maximum value of the range.)  */
+      if (incr == 1)
        {
-         unsigned HOST_WIDE_INT u_max;
-         HOST_WIDE_INT s_max;
-
-         u_end_val = start_val + (neg_incr ? -total_incr : total_incr);
-         s_end_val = u_end_val;
-         u_max = GET_MODE_MASK (biv_mode);
-         s_max = u_max >> 1;
-
-         /* Check zero extension of biv ok.  */
-         if (start_val >= 0
-             /* Check for host arithmetic overflow.  */
-             && (neg_incr
-                 ? u_end_val < u_start_val
-                 : u_end_val > u_start_val)
-             /* Check for target arithmetic overflow.  */
-             && (neg_incr
-                 ? 1 /* taken care of with host overflow */
-                 : u_end_val <= u_max))
-           {
-             ze_ok = 1;
-           }
+         if (loop_info->comparison_code == LT)
+           return true;
+         if (loop_info->comparison_code == LTU && unsignedp)
+           return true;
+       }
 
-         /* Check sign extension of biv ok.  */
-         /* ??? While it is true that overflow with signed and pointer
-            arithmetic is undefined, I fear too many programmers don't
-            keep this fact in mind -- myself included on occasion.
-            So leave alone with the signed overflow optimizations.  */
-         if (start_val >= -s_max - 1
-             /* Check for host arithmetic overflow.  */
-             && (neg_incr
-                 ? s_end_val < start_val
-                 : s_end_val > start_val)
-             /* Check for target arithmetic overflow.  */
-             && (neg_incr
-                 ? s_end_val >= -s_max - 1
-                 : s_end_val <= s_max))
-           {
-             se_ok = 1;
-           }
+      /* Likewise for increment -1 and exit test >.  */
+      if (incr == -1)
+       {
+         if (loop_info->comparison_code == GT)
+           return true;
+         if (loop_info->comparison_code == GTU && unsignedp)
+           return true;
        }
     }
+  return false;
+}
+
+
+/* Return false iff it is provable that biv BL plus BIAS will not wrap
+   at any point in its update sequence.  Note that at the rtl level we
+   may not have information about the signedness of BL; in that case,
+   check for both signed and unsigned overflow.  */
+
+static bool
+biased_biv_may_wrap_p (const struct loop *loop, struct iv_class *bl,
+                      unsigned HOST_WIDE_INT bias)
+{
+  HOST_WIDE_INT incr;
+  bool check_signed, check_unsigned;
+  enum machine_mode mode;
+
+  /* If the increment is not monotonic, we'd have to check separately
+     at each increment step.  Not Worth It.  */
+  incr = get_monotonic_increment (bl);
+  if (incr == 0)
+    return true;
 
-  /* If we know the BIV is compared at run-time against an 
-     invariant value, and the increment is +/- 1, we may also 
-     be able to prove that the BIV cannot overflow.  */
-  else if (bl->biv->src_reg == loop_info->iteration_var
-           && loop_info->comparison_value
-           && loop_invariant_p (loop, loop_info->comparison_value)
-           && (incr = biv_total_increment (bl))
-           && GET_CODE (incr) == CONST_INT)
-    {
-      /* If the increment is +1, and the exit test is a <,
-         the BIV cannot overflow.  (For <=, we have the 
-         problematic case that the comparison value might
-         be the maximum value of the range.)  */
-       if (INTVAL (incr) == 1)
-         {
-           if (loop_info->comparison_code == LT)
-             se_ok = ze_ok = 1;
-           else if (loop_info->comparison_code == LTU)
-             ze_ok = 1;
-         }
-
-       /* Likewise for increment -1 and exit test >.  */
-       if (INTVAL (incr) == -1)
-         {
-           if (loop_info->comparison_code == GT)
-             se_ok = ze_ok = 1;
-           else if (loop_info->comparison_code == GTU)
-             ze_ok = 1;
-         }
+  /* If this biv is the loop iteration variable, then we may be able to
+     deduce a sign based on the loop condition.  */
+  /* ??? This is not 100% reliable; consider an unsigned biv that is cast
+     to signed for the comparison.  However, this same bug appears all
+     through loop.c.  */
+  check_signed = check_unsigned = true;
+  if (bl->biv->src_reg == LOOP_INFO (loop)->iteration_var)
+    {
+      switch (LOOP_INFO (loop)->comparison_code)
+       {
+       case GTU: case GEU: case LTU: case LEU:
+         check_signed = false;
+         break;
+       case GT: case GE: case LT: case LE:
+         check_unsigned = false;
+         break;
+       default:
+         break;
+       }
     }
 
-  /* Invalidate givs that fail the tests.  */
-  for (v = bl->giv; v; v = v->next_iv)
-    if (v->ext_dependent)
-      {
-       enum rtx_code code = GET_CODE (v->ext_dependent);
-       int ok = 0;
+  mode = GET_MODE (bl->biv->src_reg);
 
-       switch (code)
-         {
-         case SIGN_EXTEND:
-           ok = se_ok;
-           break;
-         case ZERO_EXTEND:
-           ok = ze_ok;
-           break;
+  if (check_unsigned
+      && !biased_biv_fits_mode_p (loop, bl, incr, mode, bias))
+    return true;
 
-         case TRUNCATE:
-           /* We don't know whether this value is being used as either
-              signed or unsigned, so to safely truncate we must satisfy
-              both.  The initial check here verifies the BIV itself;
-              once that is successful we may check its range wrt the
-              derived GIV.  This works only if we were able to determine
-              constant start and end values above.  */
-           if (se_ok && ze_ok && info_ok)
-             {
-               enum machine_mode outer_mode = GET_MODE (v->ext_dependent);
-               unsigned HOST_WIDE_INT max = GET_MODE_MASK (outer_mode) >> 1;
-
-               /* We know from the above that both endpoints are nonnegative,
-                  and that there is no wrapping.  Verify that both endpoints
-                  are within the (signed) range of the outer mode.  */
-               if (u_start_val <= max && u_end_val <= max)
-                 ok = 1;
-             }
-           break;
+  if (check_signed)
+    {
+      bias += (GET_MODE_MASK (mode) >> 1) + 1;
+      if (!biased_biv_fits_mode_p (loop, bl, incr, mode, bias))
+       return true;
+    }
 
-         default:
-           abort ();
-         }
+  return false;
+}
+
+
+/* Given that X is an extension or truncation of BL, return true
+   if it is unaffected by overflow.  LOOP is the loop to which
+   BL belongs and INCR is its per-iteration increment.  */
+
+static bool
+extension_within_bounds_p (const struct loop *loop, struct iv_class *bl,
+                          HOST_WIDE_INT incr, rtx x)
+{
+  enum machine_mode mode;
+  bool signedp, unsignedp;
+
+  switch (GET_CODE (x))
+    {
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+      mode = GET_MODE (XEXP (x, 0));
+      signedp = (GET_CODE (x) == SIGN_EXTEND);
+      unsignedp = (GET_CODE (x) == ZERO_EXTEND);
+      break;
+
+    case TRUNCATE:
+      /* We don't know whether this value is being used as signed
+        or unsigned, so check the conditions for both.  */
+      mode = GET_MODE (x);
+      signedp = unsignedp = true;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return ((!signedp || biv_fits_mode_p (loop, bl, incr, mode, false))
+         && (!unsignedp || biv_fits_mode_p (loop, bl, incr, mode, true)));
+}
+
+
+/* Check each extension dependent giv in this class to see if its
+   root biv is safe from wrapping in the interior mode, which would
+   make the giv illegal.  */
+
+static void
+check_ext_dependent_givs (const struct loop *loop, struct iv_class *bl)
+{
+  struct induction *v;
+  HOST_WIDE_INT incr;
+
+  incr = get_monotonic_increment (bl);
 
-       if (ok)
+  /* Invalidate givs that fail the tests.  */
+  for (v = bl->giv; v; v = v->next_iv)
+    if (v->ext_dependent)
+      {
+       if (incr != 0
+           && extension_within_bounds_p (loop, bl, incr, v->ext_dependent))
          {
-           if (loop_dump_stream)
-             {
-               fprintf (loop_dump_stream,
-                        "Verified ext dependent giv at %d of reg %d\n",
-                        INSN_UID (v->insn), bl->regno);
-             }
+           if (dump_file)
+             fprintf (dump_file,
+                      "Verified ext dependent giv at %d of reg %d\n",
+                      INSN_UID (v->insn), bl->regno);
          }
        else
          {
-           if (loop_dump_stream)
-             {
-               const char *why;
+           if (dump_file)
+             fprintf (dump_file,
+                      "Failed ext dependent giv at %d\n",
+                      INSN_UID (v->insn));
 
-               if (info_ok)
-                 why = "biv iteration values overflowed";
-               else
-                 {
-                   if (incr == pc_rtx)
-                     incr = biv_total_increment (bl);
-                   if (incr == const1_rtx)
-                     why = "biv iteration info incomplete; incr by 1";
-                   else
-                     why = "biv iteration info incomplete";
-                 }
-
-               fprintf (loop_dump_stream,
-                        "Failed ext dependent giv at %d, %s\n",
-                        INSN_UID (v->insn), why);
-             }
            v->ignore = 1;
            bl->all_reduced = 0;
          }
@@ -8868,8 +9023,8 @@ combine_givs (struct loop_regs *regs, struct iv_class *bl)
     if (!g1->ignore)
       giv_array[i++] = g1;
 
-  stats = xcalloc (giv_count, sizeof (*stats));
-  can_combine = xcalloc (giv_count, giv_count * sizeof (rtx));
+  stats = XCNEWVEC (struct combine_givs_stats, giv_count);
+  can_combine = XCNEWVEC (rtx, giv_count * giv_count);
 
   for (i = 0; i < giv_count; i++)
     {
@@ -8882,7 +9037,7 @@ combine_givs (struct loop_regs *regs, struct iv_class *bl)
       /* If a DEST_REG GIV is used only once, do not allow it to combine
         with anything, for in doing so we will gain nothing that cannot
         be had by simply letting the GIV with which we would have combined
-        to be reduced on its own.  The losage shows up in particular with
+        to be reduced on its own.  The lossage shows up in particular with
         DEST_ADDR targets on hosts with reg+reg addressing, though it can
         be seen elsewhere as well.  */
       if (g1->giv_type == DEST_REG
@@ -8914,18 +9069,18 @@ combine_givs (struct loop_regs *regs, struct iv_class *bl)
 restart:
   qsort (stats, giv_count, sizeof (*stats), cmp_combine_givs_stats);
 
-  if (loop_dump_stream)
+  if (dump_file)
     {
-      fprintf (loop_dump_stream, "Sorted combine statistics:\n");
+      fprintf (dump_file, "Sorted combine statistics:\n");
       for (k = 0; k < giv_count; k++)
        {
          g1 = giv_array[stats[k].giv_number];
          if (!g1->combined_with && !g1->same)
-           fprintf (loop_dump_stream, " {%d, %d}",
+           fprintf (dump_file, " {%d, %d}",
                     INSN_UID (giv_array[stats[k].giv_number]->insn),
                     stats[k].total_benefit);
        }
-      putc ('\n', loop_dump_stream);
+      putc ('\n', dump_file);
     }
 
   for (k = 0; k < giv_count; k++)
@@ -8977,8 +9132,8 @@ restart:
                    stats[l].total_benefit -= g2->benefit + extra_benefit;
                }
 
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream,
+             if (dump_file)
+               fprintf (dump_file,
                         "giv at %d combined with giv at %d; new benefit %d + %d, lifetime %d\n",
                         INSN_UID (g2->insn), INSN_UID (g1->insn),
                         g1->benefit, g1_add_benefit, g1->lifetime);
@@ -9202,7 +9357,9 @@ product_cheap_p (rtx a, rtx b)
   end_sequence ();
 
   win = 1;
-  if (INSN_P (tmp))
+  if (tmp == NULL_RTX)
+    ;
+  else if (INSN_P (tmp))
     {
       n_insns = 0;
       while (tmp != NULL_RTX)
@@ -9537,8 +9694,8 @@ check_dbra_loop (struct loop *loop, int insn_count)
          rtx tem;
 
          /* Loop can be reversed.  */
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream, "Can reverse loop\n");
+         if (dump_file)
+           fprintf (dump_file, "Can reverse loop\n");
 
          /* Now check other conditions:
 
@@ -9832,13 +9989,13 @@ check_dbra_loop (struct loop *loop, int insn_count)
 
              bl->reversed = 1;
 
-             if (loop_dump_stream)
+             if (dump_file)
                {
-                 fprintf (loop_dump_stream, "Reversed loop");
+                 fprintf (dump_file, "Reversed loop");
                  if (bl->nonneg)
-                   fprintf (loop_dump_stream, " and added reg_nonneg\n");
+                   fprintf (dump_file, " and added reg_nonneg\n");
                  else
-                   fprintf (loop_dump_stream, "\n");
+                   fprintf (dump_file, "\n");
                }
 
              return 1;
@@ -9904,8 +10061,8 @@ maybe_eliminate_biv (const struct loop *loop, struct iv_class *bl,
          && ! maybe_eliminate_biv_1 (loop, PATTERN (p), p, bl,
                                      eliminate_p, where_bb, where_insn))
        {
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream,
+         if (dump_file)
+           fprintf (dump_file,
                     "Cannot eliminate biv %d: biv used in insn %d.\n",
                     bl->regno, INSN_UID (p));
          break;
@@ -9920,8 +10077,8 @@ maybe_eliminate_biv (const struct loop *loop, struct iv_class *bl,
 
   if (p == loop->end)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream, "biv %d %s eliminated.\n",
+      if (dump_file)
+       fprintf (dump_file, "biv %d %s eliminated.\n",
                 bl->regno, eliminate_p ? "was" : "can be");
       return 1;
     }
@@ -10133,195 +10290,56 @@ maybe_eliminate_biv_1 (const struct loop *loop, rtx x, rtx insn,
       else
        break;
 
-      if (CONSTANT_P (arg))
-       {
-         /* First try to replace with any giv that has constant positive
-            mult_val and constant add_val.  We might be able to support
-            negative mult_val, but it seems complex to do it in general.  */
-
-         for (v = bl->giv; v; v = v->next_iv)
-           if (GET_CODE (v->mult_val) == CONST_INT
-               && INTVAL (v->mult_val) > 0
-               && (GET_CODE (v->add_val) == SYMBOL_REF
-                   || GET_CODE (v->add_val) == LABEL_REF
-                   || GET_CODE (v->add_val) == CONST
-                   || (REG_P (v->add_val)
-                       && REG_POINTER (v->add_val)))
-               && ! v->ignore && ! v->maybe_dead && v->always_computable
-               && v->mode == mode)
-             {
-               if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
-                 continue;
-
-               /* Don't eliminate if the linear combination that makes up
-                  the giv overflows when it is applied to ARG.  */
-               if (GET_CODE (arg) == CONST_INT)
-                 {
-                   rtx add_val;
-
-                   if (GET_CODE (v->add_val) == CONST_INT)
-                     add_val = v->add_val;
-                   else
-                     add_val = const0_rtx;
-
-                   if (const_mult_add_overflow_p (arg, v->mult_val,
-                                                  add_val, mode, 1))
-                     continue;
-                 }
-
-               if (! eliminate_p)
-                 return 1;
-
-               /* Replace biv with the giv's reduced reg.  */
-               validate_change (insn, &XEXP (x, 1 - arg_operand), v->new_reg, 1);
-
-               /* If all constants are actually constant integers and
-                  the derived constant can be directly placed in the COMPARE,
-                  do so.  */
-               if (GET_CODE (arg) == CONST_INT
-                   && GET_CODE (v->add_val) == CONST_INT)
-                 {
-                   tem = expand_mult_add (arg, NULL_RTX, v->mult_val,
-                                          v->add_val, mode, 1);
-                 }
-               else
-                 {
-                   /* Otherwise, load it into a register.  */
-                   tem = gen_reg_rtx (mode);
-                   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);
-
-               if (apply_change_group ())
-                 return 1;
-             }
-
-         /* Look for giv with positive constant mult_val and nonconst add_val.
-            Insert insns to calculate new compare value.
-            ??? Turn this off due to possible overflow.  */
-
-         for (v = bl->giv; v; v = v->next_iv)
-           if (GET_CODE (v->mult_val) == CONST_INT
-               && INTVAL (v->mult_val) > 0
-               && ! v->ignore && ! v->maybe_dead && v->always_computable
-               && v->mode == mode
-               && 0)
-             {
-               rtx tem;
-
-               if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
-                 continue;
-
-               if (! eliminate_p)
-                 return 1;
-
-               tem = gen_reg_rtx (mode);
-
-               /* Replace biv with giv's reduced register.  */
-               validate_change (insn, &XEXP (x, 1 - arg_operand),
-                                v->new_reg, 1);
-
-               /* Compute value to compare against.  */
-               loop_iv_add_mult_emit_before (loop, arg,
-                                             v->mult_val, v->add_val,
-                                             tem, where_bb, where_insn);
-               /* Use it in this insn.  */
-               validate_change (insn, &XEXP (x, arg_operand), tem, 1);
-               if (apply_change_group ())
-                 return 1;
-             }
-       }
-      else if (REG_P (arg) || MEM_P (arg))
-       {
-         if (loop_invariant_p (loop, arg) == 1)
-           {
-             /* Look for giv with constant positive mult_val and nonconst
-                add_val. Insert insns to compute new compare value.
-                ??? Turn this off due to possible overflow.  */
-
-             for (v = bl->giv; v; v = v->next_iv)
-               if (GET_CODE (v->mult_val) == CONST_INT && INTVAL (v->mult_val) > 0
-                   && ! v->ignore && ! v->maybe_dead && v->always_computable
-                   && v->mode == mode
-                   && 0)
-                 {
-                   rtx tem;
-
-                   if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
-                     continue;
-
-                   if (! eliminate_p)
-                     return 1;
-
-                   tem = gen_reg_rtx (mode);
-
-                   /* Replace biv with giv's reduced register.  */
-                   validate_change (insn, &XEXP (x, 1 - arg_operand),
-                                    v->new_reg, 1);
-
-                   /* Compute value to compare against.  */
-                   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);
-                   if (apply_change_group ())
-                     return 1;
-                 }
-           }
-
-         /* This code has problems.  Basically, you can't know when
-            seeing if we will eliminate BL, whether a particular giv
-            of ARG will be reduced.  If it isn't going to be reduced,
-            we can't eliminate BL.  We can try forcing it to be reduced,
-            but that can generate poor code.
+      if (GET_CODE (arg) != CONST_INT)
+       return 0;
 
-            The problem is that the benefit of reducing TV, below should
-            be increased if BL can actually be eliminated, but this means
-            we might have to do a topological sort of the order in which
-            we try to process biv.  It doesn't seem worthwhile to do
-            this sort of thing now.  */
+      /* Unless we're dealing with an equality comparison, if we can't
+        determine that the original biv doesn't wrap, then we must not
+        apply the transformation.  */
+      /* ??? Actually, what we must do is verify that the transformed
+        giv doesn't wrap.  But the general case of this transformation
+        was disabled long ago due to wrapping problems, and there's no
+        point reviving it this close to end-of-life for loop.c.  The
+        only case still enabled is known (via the check on add_val) to
+        be pointer arithmetic, which in theory never overflows for
+        valid programs.  */
+      /* Without lifetime analysis, we don't know how COMPARE will be
+        used, so we must assume the worst.  */
+      if (code != EQ && code != NE
+         && biased_biv_may_wrap_p (loop, bl, INTVAL (arg)))
+       return 0;
 
-#if 0
-         /* Otherwise the reg compared with had better be a biv.  */
-         if (!REG_P (arg)
-             || REG_IV_TYPE (ivs, REGNO (arg)) != BASIC_INDUCT)
-           return 0;
+      /* Try to replace with any giv that has constant positive mult_val
+         and a pointer add_val.  */
+      for (v = bl->giv; v; v = v->next_iv)
+       if (GET_CODE (v->mult_val) == CONST_INT
+           && INTVAL (v->mult_val) > 0
+           && (GET_CODE (v->add_val) == SYMBOL_REF
+               || GET_CODE (v->add_val) == LABEL_REF
+               || GET_CODE (v->add_val) == CONST
+               || (REG_P (v->add_val) && REG_POINTER (v->add_val)))
+           && ! v->ignore && ! v->maybe_dead && v->always_computable
+           && v->mode == mode)
+         {
+           if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
+             continue;
 
-         /* Look for a pair of givs, one for each biv,
-            with identical coefficients.  */
-         for (v = bl->giv; v; v = v->next_iv)
-           {
-             struct induction *tv;
+           if (! eliminate_p)
+             return 1;
 
-             if (v->ignore || v->maybe_dead || v->mode != mode)
-               continue;
+           /* Replace biv with the giv's reduced reg.  */
+           validate_change (insn, &XEXP (x, 1 - arg_operand), v->new_reg, 1);
 
-             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)
-                   && rtx_equal_p (tv->add_val, v->add_val)
-                   && tv->mode == mode)
-                 {
-                   if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
-                     continue;
+           /* Load the value into a register.  */
+           tem = gen_reg_rtx (mode);
+           loop_iv_add_mult_emit_before (loop, arg, v->mult_val, v->add_val,
+                                         tem, where_bb, where_insn);
 
-                   if (! eliminate_p)
-                     return 1;
+           validate_change (insn, &XEXP (x, arg_operand), tem, 1);
 
-                   /* Replace biv with its giv's reduced reg.  */
-                   XEXP (x, 1 - arg_operand) = v->new_reg;
-                   /* Replace other operand with the other giv's
-                      reduced reg.  */
-                   XEXP (x, arg_operand) = tv->new_reg;
-                   return 1;
-                 }
-           }
-#endif
-       }
+           if (apply_change_group ())
+             return 1;
+         }
 
       /* If we get here, the biv can't be eliminated.  */
       return 0;
@@ -10438,319 +10456,8 @@ update_reg_last_use (rtx x, rtx insn)
     }
 }
 \f
-/* Given an insn INSN and condition COND, return the condition in a
-   canonical form to simplify testing by callers.  Specifically:
-
-   (1) The code will always be a comparison operation (EQ, NE, GT, etc.).
-   (2) Both operands will be machine operands; (cc0) will have been replaced.
-   (3) If an operand is a constant, it will be the second operand.
-   (4) (LE x const) will be replaced with (LT x <const+1>) and similarly
-       for GE, GEU, and LEU.
-
-   If the condition cannot be understood, or is an inequality floating-point
-   comparison which needs to be reversed, 0 will be returned.
-
-   If REVERSE is nonzero, then reverse the condition prior to canonizing it.
-
-   If EARLIEST is nonzero, it is a pointer to a place where the earliest
-   insn used in locating the condition was found.  If a replacement test
-   of the condition is desired, it should be placed in front of that
-   insn and we will be sure that the inputs are still valid.
-
-   If WANT_REG is nonzero, we wish the condition to be relative to that
-   register, if possible.  Therefore, do not canonicalize the condition
-   further.  If ALLOW_CC_MODE is nonzero, allow the condition returned 
-   to be a compare to a CC mode register.
-
-   If VALID_AT_INSN_P, the condition must be valid at both *EARLIEST
-   and at INSN.  */
-
-rtx
-canonicalize_condition (rtx insn, rtx cond, int reverse, rtx *earliest,
-                       rtx want_reg, int allow_cc_mode, int valid_at_insn_p)
-{
-  enum rtx_code code;
-  rtx prev = insn;
-  rtx set;
-  rtx tem;
-  rtx op0, op1;
-  int reverse_code = 0;
-  enum machine_mode mode;
-
-  code = GET_CODE (cond);
-  mode = GET_MODE (cond);
-  op0 = XEXP (cond, 0);
-  op1 = XEXP (cond, 1);
-
-  if (reverse)
-    code = reversed_comparison_code (cond, insn);
-  if (code == UNKNOWN)
-    return 0;
-
-  if (earliest)
-    *earliest = insn;
-
-  /* If we are comparing a register with zero, see if the register is set
-     in the previous insn to a COMPARE or a comparison operation.  Perform
-     the same tests as a function of STORE_FLAG_VALUE as find_comparison_args
-     in cse.c  */
-
-  while ((GET_RTX_CLASS (code) == RTX_COMPARE
-         || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
-        && op1 == CONST0_RTX (GET_MODE (op0))
-        && op0 != want_reg)
-    {
-      /* Set nonzero when we find something of interest.  */
-      rtx x = 0;
-
-#ifdef HAVE_cc0
-      /* If comparison with cc0, import actual comparison from compare
-        insn.  */
-      if (op0 == cc0_rtx)
-       {
-         if ((prev = prev_nonnote_insn (prev)) == 0
-             || !NONJUMP_INSN_P (prev)
-             || (set = single_set (prev)) == 0
-             || SET_DEST (set) != cc0_rtx)
-           return 0;
-
-         op0 = SET_SRC (set);
-         op1 = CONST0_RTX (GET_MODE (op0));
-         if (earliest)
-           *earliest = prev;
-       }
-#endif
-
-      /* If this is a COMPARE, pick up the two things being compared.  */
-      if (GET_CODE (op0) == COMPARE)
-       {
-         op1 = XEXP (op0, 1);
-         op0 = XEXP (op0, 0);
-         continue;
-       }
-      else if (!REG_P (op0))
-       break;
-
-      /* Go back to the previous insn.  Stop if it is not an INSN.  We also
-        stop if it isn't a single set or if it has a REG_INC note because
-        we don't want to bother dealing with it.  */
-
-      if ((prev = prev_nonnote_insn (prev)) == 0
-         || !NONJUMP_INSN_P (prev)
-         || FIND_REG_INC_NOTE (prev, NULL_RTX))
-       break;
-
-      set = set_of (op0, prev);
-
-      if (set
-         && (GET_CODE (set) != SET
-             || !rtx_equal_p (SET_DEST (set), op0)))
-       break;
-
-      /* If this is setting OP0, get what it sets it to if it looks
-        relevant.  */
-      if (set)
-       {
-         enum machine_mode inner_mode = GET_MODE (SET_DEST (set));
-#ifdef FLOAT_STORE_FLAG_VALUE
-         REAL_VALUE_TYPE fsfv;
-#endif
-
-         /* ??? We may not combine comparisons done in a CCmode with
-            comparisons not done in a CCmode.  This is to aid targets
-            like Alpha that have an IEEE compliant EQ instruction, and
-            a non-IEEE compliant BEQ instruction.  The use of CCmode is
-            actually artificial, simply to prevent the combination, but
-            should not affect other platforms.
-
-            However, we must allow VOIDmode comparisons to match either
-            CCmode or non-CCmode comparison, because some ports have
-            modeless comparisons inside branch patterns.
-
-            ??? This mode check should perhaps look more like the mode check
-            in simplify_comparison in combine.  */
-
-         if ((GET_CODE (SET_SRC (set)) == COMPARE
-              || (((code == NE
-                    || (code == LT
-                        && GET_MODE_CLASS (inner_mode) == MODE_INT
-                        && (GET_MODE_BITSIZE (inner_mode)
-                            <= HOST_BITS_PER_WIDE_INT)
-                        && (STORE_FLAG_VALUE
-                            & ((HOST_WIDE_INT) 1
-                               << (GET_MODE_BITSIZE (inner_mode) - 1))))
-#ifdef FLOAT_STORE_FLAG_VALUE
-                    || (code == LT
-                        && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                        && (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
-                            REAL_VALUE_NEGATIVE (fsfv)))
-#endif
-                    ))
-                  && COMPARISON_P (SET_SRC (set))))
-             && (((GET_MODE_CLASS (mode) == MODE_CC)
-                  == (GET_MODE_CLASS (inner_mode) == MODE_CC))
-                 || mode == VOIDmode || inner_mode == VOIDmode))
-           x = SET_SRC (set);
-         else if (((code == EQ
-                    || (code == GE
-                        && (GET_MODE_BITSIZE (inner_mode)
-                            <= HOST_BITS_PER_WIDE_INT)
-                        && GET_MODE_CLASS (inner_mode) == MODE_INT
-                        && (STORE_FLAG_VALUE
-                            & ((HOST_WIDE_INT) 1
-                               << (GET_MODE_BITSIZE (inner_mode) - 1))))
-#ifdef FLOAT_STORE_FLAG_VALUE
-                    || (code == GE
-                        && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                        && (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
-                            REAL_VALUE_NEGATIVE (fsfv)))
-#endif
-                    ))
-                  && COMPARISON_P (SET_SRC (set))
-                  && (((GET_MODE_CLASS (mode) == MODE_CC)
-                       == (GET_MODE_CLASS (inner_mode) == MODE_CC))
-                      || mode == VOIDmode || inner_mode == VOIDmode))
-
-           {
-             reverse_code = 1;
-             x = SET_SRC (set);
-           }
-         else
-           break;
-       }
-
-      else if (reg_set_p (op0, prev))
-       /* If this sets OP0, but not directly, we have to give up.  */
-       break;
-
-      if (x)
-       {
-         /* If the caller is expecting the condition to be valid at INSN,
-            make sure X doesn't change before INSN.  */
-         if (valid_at_insn_p)
-           if (modified_in_p (x, prev) || modified_between_p (x, prev, insn))
-             break;
-         if (COMPARISON_P (x))
-           code = GET_CODE (x);
-         if (reverse_code)
-           {
-             code = reversed_comparison_code (x, prev);
-             if (code == UNKNOWN)
-               return 0;
-             reverse_code = 0;
-           }
-
-         op0 = XEXP (x, 0), op1 = XEXP (x, 1);
-         if (earliest)
-           *earliest = prev;
-       }
-    }
-
-  /* If constant is first, put it last.  */
-  if (CONSTANT_P (op0))
-    code = swap_condition (code), tem = op0, op0 = op1, op1 = tem;
-
-  /* If OP0 is the result of a comparison, we weren't able to find what
-     was really being compared, so fail.  */
-  if (!allow_cc_mode
-      && GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
-    return 0;
-
-  /* Canonicalize any ordered comparison with integers involving equality
-     if we can do computations in the relevant mode and we do not
-     overflow.  */
-
-  if (GET_MODE_CLASS (GET_MODE (op0)) != MODE_CC
-      && GET_CODE (op1) == CONST_INT
-      && GET_MODE (op0) != VOIDmode
-      && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
-    {
-      HOST_WIDE_INT const_val = INTVAL (op1);
-      unsigned HOST_WIDE_INT uconst_val = const_val;
-      unsigned HOST_WIDE_INT max_val
-       = (unsigned HOST_WIDE_INT) GET_MODE_MASK (GET_MODE (op0));
-
-      switch (code)
-       {
-       case LE:
-         if ((unsigned HOST_WIDE_INT) const_val != max_val >> 1)
-           code = LT, op1 = gen_int_mode (const_val + 1, GET_MODE (op0));
-         break;
-
-       /* When cross-compiling, const_val might be sign-extended from
-          BITS_PER_WORD to HOST_BITS_PER_WIDE_INT */
-       case GE:
-         if ((HOST_WIDE_INT) (const_val & max_val)
-             != (((HOST_WIDE_INT) 1
-                  << (GET_MODE_BITSIZE (GET_MODE (op0)) - 1))))
-           code = GT, op1 = gen_int_mode (const_val - 1, GET_MODE (op0));
-         break;
-
-       case LEU:
-         if (uconst_val < max_val)
-           code = LTU, op1 = gen_int_mode (uconst_val + 1, GET_MODE (op0));
-         break;
-
-       case GEU:
-         if (uconst_val != 0)
-           code = GTU, op1 = gen_int_mode (uconst_val - 1, GET_MODE (op0));
-         break;
-
-       default:
-         break;
-       }
-    }
-
-  /* Never return CC0; return zero instead.  */
-  if (CC0_P (op0))
-    return 0;
-
-  return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
-}
-
-/* Given a jump insn JUMP, return the condition that will cause it to branch
-   to its JUMP_LABEL.  If the condition cannot be understood, or is an
-   inequality floating-point comparison which needs to be reversed, 0 will
-   be returned.
-
-   If EARLIEST is nonzero, it is a pointer to a place where the earliest
-   insn used in locating the condition was found.  If a replacement test
-   of the condition is desired, it should be placed in front of that
-   insn and we will be sure that the inputs are still valid.  If EARLIEST
-   is null, the returned condition will be valid at INSN.
-
-   If ALLOW_CC_MODE is nonzero, allow the condition returned to be a
-   compare CC mode register.
-
-   VALID_AT_INSN_P is the same as for canonicalize_condition.  */
-
-rtx
-get_condition (rtx jump, rtx *earliest, int allow_cc_mode, int valid_at_insn_p)
-{
-  rtx cond;
-  int reverse;
-  rtx set;
-
-  /* If this is not a standard conditional jump, we can't parse it.  */
-  if (!JUMP_P (jump)
-      || ! any_condjump_p (jump))
-    return 0;
-  set = pc_set (jump);
-
-  cond = XEXP (SET_SRC (set), 0);
-
-  /* If this branches to JUMP_LABEL when the condition is false, reverse
-     the condition.  */
-  reverse
-    = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
-      && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump);
-
-  return canonicalize_condition (jump, cond, reverse, earliest, NULL_RTX,
-                                allow_cc_mode, valid_at_insn_p);
-}
-
-/* Similar to above routine, except that we also put an invariant last
-   unless both operands are invariants.  */
+/* Similar to rtlanal.c:get_condition, except that we also put an
+   invariant last unless both operands are invariants.  */
 
 static rtx
 get_condition_for_loop (const struct loop *loop, rtx x)
@@ -10909,7 +10616,7 @@ loop_regs_scan (const struct loop *loop, int extra_size)
       regs->array[i].single_usage = NULL_RTX;
     }
 
-  last_set = xcalloc (regs->num, sizeof (rtx));
+  last_set = XCNEWVEC (rtx, regs->num);
 
   /* Scan the loop, recording register usage.  */
   for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
@@ -11119,9 +10826,16 @@ load_mems (const struct loop *loop)
        }
 
       if (flag_float_store && written
-         && GET_MODE_CLASS (GET_MODE (mem)) == MODE_FLOAT)
+         && SCALAR_FLOAT_MODE_P (GET_MODE (mem)))
        loop_info->mems[i].optimize = 0;
 
+#ifdef STACK_REGS
+      /* Don't hoist constant pool constants into stack registers.  */
+      if (IS_STACK_MODE (GET_MODE (mem))
+          && constant_pool_constant_p (mem))
+       loop_info->mems[i].optimize = 0;
+#endif
+
       /* If this MEM is written to, we must be sure that there
         are no reads from another MEM that aliases this one.  */
       if (loop_info->mems[i].optimize && written)
@@ -11240,8 +10954,9 @@ load_mems (const struct loop *loop)
          cselib_val *e = cselib_lookup (mem, VOIDmode, 0);
          rtx set;
          rtx best = mem;
-         int j;
+         unsigned j;
          struct elt_loc_list *const_equiv = 0;
+         reg_set_iterator rsi;
 
          if (e)
            {
@@ -11308,29 +11023,29 @@ load_mems (const struct loop *loop)
              loop_insn_emit_after (loop, 0, label, set);
            }
 
-         if (loop_dump_stream)
+         if (dump_file)
            {
-             fprintf (loop_dump_stream, "Hoisted regno %d %s from ",
+             fprintf (dump_file, "Hoisted regno %d %s from ",
                       REGNO (reg), (written ? "r/w" : "r/o"));
-             print_rtl (loop_dump_stream, mem);
-             fputc ('\n', loop_dump_stream);
+             print_rtl (dump_file, mem);
+             fputc ('\n', dump_file);
            }
 
          /* Attempt a bit of copy propagation.  This helps untangle the
             data flow, and enables {basic,general}_induction_var to find
             more bivs/givs.  */
          EXECUTE_IF_SET_IN_REG_SET
-           (&load_copies, FIRST_PSEUDO_REGISTER, j,
-            {
-              try_copy_prop (loop, reg, j);
-            });
+           (&load_copies, FIRST_PSEUDO_REGISTER, j, rsi)
+           {
+             try_copy_prop (loop, reg, j);
+           }
          CLEAR_REG_SET (&load_copies);
 
          EXECUTE_IF_SET_IN_REG_SET
-           (&store_copies, FIRST_PSEUDO_REGISTER, j,
-            {
-              try_swap_copy_prop (loop, reg, j);
-            });
+           (&store_copies, FIRST_PSEUDO_REGISTER, j, rsi)
+           {
+             try_swap_copy_prop (loop, reg, j);
+           }
          CLEAR_REG_SET (&store_copies);
        }
     }
@@ -11398,8 +11113,7 @@ try_copy_prop (const struct loop *loop, rtx replacement, unsigned int regno)
          && REG_P (SET_DEST (set))
          && REGNO (SET_DEST (set)) == regno)
        {
-         if (init_insn)
-           abort ();
+         gcc_assert (!init_insn);
 
          init_insn = insn;
          if (REGNO_FIRST_UID (regno) == INSN_UID (insn))
@@ -11432,12 +11146,11 @@ try_copy_prop (const struct loop *loop, rtx replacement, unsigned int regno)
            }
        }
     }
-  if (! init_insn)
-    abort ();
+  gcc_assert (init_insn);
   if (apply_change_group ())
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream, "  Replaced reg %d", regno);
+      if (dump_file)
+       fprintf (dump_file, "  Replaced reg %d", regno);
       if (store_is_first && replaced_last)
        {
          rtx first;
@@ -11456,8 +11169,8 @@ try_copy_prop (const struct loop *loop, rtx replacement, unsigned int regno)
          /* Delete the instructions.  */
          loop_delete_insns (first, init_insn);
        }
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream, ".\n");
+      if (dump_file)
+       fprintf (dump_file, ".\n");
     }
 }
 
@@ -11469,8 +11182,8 @@ loop_delete_insns (rtx first, rtx last)
 {
   while (1)
     {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream, ", deleting init_insn (%d)",
+      if (dump_file)
+       fprintf (dump_file, ", deleting init_insn (%d)",
                 INSN_UID (first));
       delete_insn (first);
 
@@ -11550,8 +11263,8 @@ try_swap_copy_prop (const struct loop *loop, rtx replacement,
 
          if (apply_change_group ())
            {
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream,
+             if (dump_file)
+               fprintf (dump_file,
                         "  Swapped set of reg %d at %d with reg %d at %d.\n",
                         regno, INSN_UID (insn),
                         new_regno, INSN_UID (prev_insn));
@@ -11934,7 +11647,7 @@ loop_giv_dump (const struct induction *v, FILE *file, int verbose)
          fprintf (file, " ext tr");
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
 
@@ -12063,3 +11776,66 @@ debug_loops (const struct loops *loops)
 {
   flow_loops_dump (loops, stderr, loop_dump_aux, 1);
 }
+\f
+static bool
+gate_handle_loop_optimize (void)
+{
+  return (optimize > 0 && flag_loop_optimize);
+}
+
+/* Move constant computations out of loops.  */
+static void
+rest_of_handle_loop_optimize (void)
+{
+  int do_prefetch;
+
+  /* CFG is no longer maintained up-to-date.  */
+  free_bb_for_insn ();
+  profile_status = PROFILE_ABSENT;
+  
+  do_prefetch = flag_prefetch_loop_arrays == 2 ? LOOP_PREFETCH : 0;
+  
+  if (flag_rerun_loop_opt)
+    {
+      cleanup_barriers ();
+      
+      /* We only want to perform unrolling once.  */
+      loop_optimize (get_insns (), 0);
+      
+      /* The first call to loop_optimize makes some instructions
+         trivially dead.  We delete those instructions now in the
+         hope that doing so will make the heuristics in loop work
+         better and possibly speed up compilation.  */
+      delete_trivially_dead_insns (get_insns (), max_reg_num ());
+  
+      /* The regscan pass is currently necessary as the alias
+         analysis code depends on this information.  */
+      reg_scan (get_insns (), max_reg_num ());
+    } 
+  cleanup_barriers ();
+  loop_optimize (get_insns (), do_prefetch);
+      
+  /* Loop can create trivially dead instructions.  */
+  delete_trivially_dead_insns (get_insns (), max_reg_num ());
+  find_basic_blocks (get_insns ());
+}
+
+struct tree_opt_pass pass_loop_optimize =
+{
+  "old-loop",                           /* name */
+  gate_handle_loop_optimize,            /* gate */   
+  rest_of_handle_loop_optimize,         /* execute */       
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_LOOP,                              /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  'L'                                   /* letter */
+};
+
+