OSDN Git Service

Fix copyright problems reported by Doug Evans.
[pf3gnuchains/gcc-fork.git] / gcc / loop.c
index 57b4555..cc09454 100644 (file)
@@ -1,23 +1,23 @@
 /* Perform various loop optimizations, including strength reduction.
    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 /* This is the loop optimization pass of the compiler.
    It finds invariant computations within loops and moves them
@@ -36,15 +36,15 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tm_p.h"
-#include "obstack.h"
 #include "function.h"
 #include "expr.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "insn-config.h"
-#include "insn-flags.h"
 #include "regs.h"
 #include "recog.h"
 #include "flags.h"
@@ -53,6 +53,108 @@ Boston, MA 02111-1307, USA.  */
 #include "cselib.h"
 #include "except.h"
 #include "toplev.h"
+#include "predict.h"
+#include "insn-flags.h"
+#include "optabs.h"
+#include "cfgloop.h"
+
+/* Not really meaningful values, but at least something.  */
+#ifndef SIMULTANEOUS_PREFETCHES
+#define SIMULTANEOUS_PREFETCHES 3
+#endif
+#ifndef PREFETCH_BLOCK
+#define PREFETCH_BLOCK 32
+#endif
+#ifndef HAVE_prefetch
+#define HAVE_prefetch 0
+#define CODE_FOR_prefetch 0
+#define gen_prefetch(a,b,c) (abort(), NULL_RTX)
+#endif
+
+/* Give up the prefetch optimizations once we exceed a given threshhold.
+   It is unlikely that we would be able to optimize something in a loop
+   with so many detected prefetches.  */
+#define MAX_PREFETCHES 100
+/* The number of prefetch blocks that are beneficial to fetch at once before
+   a loop with a known (and low) iteration count.  */
+#define PREFETCH_BLOCKS_BEFORE_LOOP_MAX  6
+/* For very tiny loops it is not worthwhile to prefetch even before the loop,
+   since it is likely that the data are already in the cache.  */
+#define PREFETCH_BLOCKS_BEFORE_LOOP_MIN  2
+
+/* Parameterize some prefetch heuristics so they can be turned on and off
+   easily for performance testing on new architectures.  These can be
+   defined in target-dependent files.  */
+
+/* Prefetch is worthwhile only when loads/stores are dense.  */
+#ifndef PREFETCH_ONLY_DENSE_MEM
+#define PREFETCH_ONLY_DENSE_MEM 1
+#endif
+
+/* Define what we mean by "dense" loads and stores; This value divided by 256
+   is the minimum percentage of memory references that worth prefetching.  */
+#ifndef PREFETCH_DENSE_MEM
+#define PREFETCH_DENSE_MEM 220
+#endif
+
+/* Do not prefetch for a loop whose iteration count is known to be low.  */
+#ifndef PREFETCH_NO_LOW_LOOPCNT
+#define PREFETCH_NO_LOW_LOOPCNT 1
+#endif
+
+/* Define what we mean by a "low" iteration count.  */
+#ifndef PREFETCH_LOW_LOOPCNT
+#define PREFETCH_LOW_LOOPCNT 32
+#endif
+
+/* Do not prefetch for a loop that contains a function call; such a loop is
+   probably not an internal loop.  */
+#ifndef PREFETCH_NO_CALL
+#define PREFETCH_NO_CALL 1
+#endif
+
+/* Do not prefetch accesses with an extreme stride.  */
+#ifndef PREFETCH_NO_EXTREME_STRIDE
+#define PREFETCH_NO_EXTREME_STRIDE 1
+#endif
+
+/* Define what we mean by an "extreme" stride.  */
+#ifndef PREFETCH_EXTREME_STRIDE
+#define PREFETCH_EXTREME_STRIDE 4096
+#endif
+
+/* Define a limit to how far apart indices can be and still be merged
+   into a single prefetch.  */
+#ifndef PREFETCH_EXTREME_DIFFERENCE
+#define PREFETCH_EXTREME_DIFFERENCE 4096
+#endif
+
+/* Issue prefetch instructions before the loop to fetch data to be used
+   in the first few loop iterations.  */
+#ifndef PREFETCH_BEFORE_LOOP
+#define PREFETCH_BEFORE_LOOP 1
+#endif
+
+/* Do not handle reversed order prefetches (negative stride).  */
+#ifndef PREFETCH_NO_REVERSE_ORDER
+#define PREFETCH_NO_REVERSE_ORDER 1
+#endif
+
+/* Prefetch even if the GIV is in conditional code.  */
+#ifndef PREFETCH_CONDITIONAL
+#define PREFETCH_CONDITIONAL 1
+#endif
+
+#define LOOP_REG_LIFETIME(LOOP, REGNO) \
+((REGNO_LAST_LUID (REGNO) - REGNO_FIRST_LUID (REGNO)))
+
+#define LOOP_REG_GLOBAL_P(LOOP, REGNO) \
+((REGNO_LAST_LUID (REGNO) > INSN_LUID ((LOOP)->end) \
+ || REGNO_FIRST_LUID (REGNO) < INSN_LUID ((LOOP)->start)))
+
+#define LOOP_REGNO_NREGS(REGNO, SET_DEST) \
+((REGNO) < FIRST_PSEUDO_REGISTER \
+ ? (int) HARD_REGNO_NREGS ((REGNO), GET_MODE (SET_DEST)) : 1)
 
 
 /* Vector mapping INSN_UIDs to luids.
@@ -70,10 +172,6 @@ struct loop **uid_loop;
 
 int max_uid_for_loop;
 
-/* 1 + luid of last insn.  */
-
-static int max_luid;
-
 /* Number of loops detected in current function.  Used as index to the
    next few tables.  */
 
@@ -85,9 +183,6 @@ unsigned int max_reg_before_loop;
 
 /* The value to pass to the next call of reg_scan_update.  */
 static int loop_max_reg;
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
 \f
 /* During the analysis of a loop, a chain of `struct movable's
    is made to record all the movable insns found.
@@ -109,6 +204,9 @@ struct movable
   short savings;               /* Number of insns we can move for this reg,
                                   including other movables that force this
                                   or match this one.  */
+  ENUM_BITFIELD(machine_mode) savemode : 8;   /* Nonzero means it is a mode for 
+                                  a low part that we should avoid changing when
+                                  clearing the rest of the reg.  */
   unsigned int cond : 1;       /* 1 if only conditionally movable */
   unsigned int force : 1;      /* 1 means MUST move this insn */
   unsigned int global : 1;     /* 1 means reg is live outside this loop */
@@ -125,9 +223,9 @@ struct movable
   unsigned int move_insn_first:1;/* Same as above, if this is necessary for the
                                    first insn of a consecutive sets group.  */
   unsigned int is_equiv : 1;   /* 1 means a REG_EQUIV is present on INSN.  */
-  enum machine_mode savemode;   /* Nonzero means it is a mode for a low part
-                                  that we should avoid changing when clearing
-                                  the rest of the reg.  */
+  unsigned int insert_temp : 1;  /* 1 means we copy to a new pseudo and replace
+                                   the original insn with a copy from that
+                                   pseudo, rather than deleting it.  */
   struct movable *match;       /* First entry for same value */
   struct movable *forces;      /* An insn that must be moved if this is */
   struct movable *next;
@@ -138,6 +236,7 @@ FILE *loop_dump_stream;
 
 /* Forward declarations.  */
 
+static void invalidate_loops_containing_label PARAMS ((rtx));
 static void find_and_verify_loops PARAMS ((rtx, struct loops *));
 static void mark_loop_jump PARAMS ((rtx, struct loop *));
 static void prescan_loop PARAMS ((struct loop *));
@@ -145,12 +244,7 @@ static int reg_in_basic_block_p PARAMS ((rtx, rtx));
 static int consec_sets_invariant_p PARAMS ((const struct loop *,
                                            rtx, int, rtx));
 static int labels_in_range_p PARAMS ((rtx, int));
-static void count_one_set PARAMS ((struct loop_regs *, rtx, rtx,
-                                  varray_type, rtx *));
-
-static void count_loop_regs_set PARAMS ((const struct loop*,
-                                        varray_type, varray_type,
-                                        int *, int));
+static void count_one_set PARAMS ((struct loop_regs *, rtx, rtx, rtx *));
 static void note_addr_stored PARAMS ((rtx, rtx, void *));
 static void note_set_pseudo_multiple_uses PARAMS ((rtx, rtx, void *));
 static int loop_reg_used_before_p PARAMS ((const struct loop *, rtx, rtx));
@@ -164,6 +258,7 @@ static void ignore_some_movables PARAMS ((struct loop_movables *));
 static void force_movables PARAMS ((struct loop_movables *));
 static void combine_movables PARAMS ((struct loop_movables *,
                                      struct loop_regs *));
+static int num_unmoved_movables PARAMS ((const struct loop *));
 static int regs_match_p PARAMS ((rtx, rtx, struct loop_movables *));
 static int rtx_equal_for_loop_p PARAMS ((rtx, rtx, struct loop_movables *,
                                         struct loop_regs *));
@@ -174,8 +269,22 @@ static void loop_movables_add PARAMS((struct loop_movables *,
                                      struct movable *));
 static void loop_movables_free PARAMS((struct loop_movables *));
 static int count_nonfixed_reads PARAMS ((const struct loop *, rtx));
-static void strength_reduce PARAMS ((struct loop *, int, int));
-static void find_single_use_in_loop PARAMS ((rtx, rtx, varray_type));
+static void loop_bivs_find PARAMS((struct loop *));
+static void loop_bivs_init_find PARAMS((struct loop *));
+static void loop_bivs_check PARAMS((struct loop *));
+static void loop_givs_find PARAMS((struct loop *));
+static void loop_givs_check PARAMS((struct loop *));
+static int loop_biv_eliminable_p PARAMS((struct loop *, struct iv_class *,
+                                        int, int));
+static int loop_giv_reduce_benefit PARAMS((struct loop *, struct iv_class *,
+                                          struct induction *, rtx));
+static void loop_givs_dead_check PARAMS((struct loop *, struct iv_class *));
+static void loop_givs_reduce PARAMS((struct loop *, struct iv_class *));
+static void loop_givs_rescan PARAMS((struct loop *, struct iv_class *,
+                                    rtx *));
+static void loop_ivs_free PARAMS((struct loop *));
+static void strength_reduce PARAMS ((struct loop *, int));
+static void find_single_use_in_loop PARAMS ((struct loop_regs *, rtx, rtx));
 static int valid_initial_value_p PARAMS ((rtx, rtx, int, rtx));
 static void find_mem_givs PARAMS ((const struct loop *, rtx, rtx, int, int));
 static void record_biv PARAMS ((struct loop *, struct induction *,
@@ -183,11 +292,15 @@ static void record_biv PARAMS ((struct loop *, struct induction *,
                                int, int));
 static void check_final_value PARAMS ((const struct loop *,
                                       struct induction *));
+static void loop_ivs_dump PARAMS((const struct loop *, FILE *, int));
+static void loop_iv_class_dump PARAMS((const struct iv_class *, FILE *, int));
+static void loop_biv_dump PARAMS((const struct induction *, FILE *, int));
+static void loop_giv_dump PARAMS((const struct induction *, FILE *, int));
 static void record_giv PARAMS ((const struct loop *, struct induction *,
                                rtx, rtx, rtx, rtx, rtx, rtx, int,
                                enum g_types, int, int, rtx *));
 static void update_giv_derive PARAMS ((const struct loop *, rtx));
-static void check_ext_dependant_givs PARAMS ((struct iv_class *,
+static void check_ext_dependent_givs PARAMS ((struct iv_class *,
                                              struct loop_info *));
 static int basic_induction_var PARAMS ((const struct loop *, rtx,
                                        enum machine_mode, rtx, rtx,
@@ -207,38 +320,50 @@ static int product_cheap_p PARAMS ((rtx, rtx));
 static int maybe_eliminate_biv PARAMS ((const struct loop *, struct iv_class *,
                                        int, int, int));
 static int maybe_eliminate_biv_1 PARAMS ((const struct loop *, rtx, rtx,
-                                         struct iv_class *, int, rtx));
+                                         struct iv_class *, int,
+                                         basic_block, rtx));
 static int last_use_this_basic_block PARAMS ((rtx, rtx));
 static void record_initial PARAMS ((rtx, rtx, void *));
 static void update_reg_last_use PARAMS ((rtx, rtx));
 static rtx next_insn_in_loop PARAMS ((const struct loop *, rtx));
-static void load_mems_and_recount_loop_regs_set PARAMS ((const struct loop*,
-                                                        int *));
+static void loop_regs_scan PARAMS ((const struct loop *, int));
+static int count_insns_in_loop PARAMS ((const struct loop *));
+static int find_mem_in_note_1 PARAMS ((rtx *, void *));
+static rtx find_mem_in_note PARAMS ((rtx));
 static void load_mems PARAMS ((const struct loop *));
 static int insert_loop_mem PARAMS ((rtx *, void *));
 static int replace_loop_mem PARAMS ((rtx *, void *));
-static void replace_loop_mems PARAMS ((rtx, rtx, rtx));
+static void replace_loop_mems PARAMS ((rtx, rtx, rtx, int));
 static int replace_loop_reg PARAMS ((rtx *, void *));
 static void replace_loop_regs PARAMS ((rtx insn, rtx, rtx));
 static void note_reg_stored PARAMS ((rtx, rtx, void *));
 static void try_copy_prop PARAMS ((const struct loop *, rtx, unsigned int));
 static void try_swap_copy_prop PARAMS ((const struct loop *, rtx,
                                         unsigned int));
-static int replace_label PARAMS ((rtx *, void *));
 static rtx check_insn_for_givs PARAMS((struct loop *, rtx, int, int));
 static rtx check_insn_for_bivs PARAMS((struct loop *, rtx, int, int));
+static rtx gen_add_mult PARAMS ((rtx, rtx, rtx, rtx));
+static void loop_regs_update PARAMS ((const struct loop *, rtx));
 static int iv_add_mult_cost PARAMS ((rtx, rtx, rtx, rtx));
 
+static rtx loop_insn_emit_after PARAMS((const struct loop *, basic_block,
+                                       rtx, rtx));
+static rtx loop_call_insn_emit_before PARAMS((const struct loop *,
+                                             basic_block, rtx, rtx));
+static rtx loop_call_insn_hoist PARAMS((const struct loop *, rtx));
+static rtx loop_insn_sink_or_swim PARAMS((const struct loop *, rtx));
+
 static void loop_dump_aux PARAMS ((const struct loop *, FILE *, int));
+static void loop_delete_insns PARAMS ((rtx, rtx));
+static HOST_WIDE_INT remove_constant_addition PARAMS ((rtx *));
+static rtx gen_load_of_final_value PARAMS ((rtx, rtx));
+void debug_ivs PARAMS ((const struct loop *));
+void debug_iv_class PARAMS ((const struct iv_class *));
+void debug_biv PARAMS ((const struct induction *));
+void debug_giv PARAMS ((const struct induction *));
 void debug_loop PARAMS ((const struct loop *));
 void debug_loops PARAMS ((const struct loops *));
 
-typedef struct rtx_pair
-{
-  rtx r1;
-  rtx r2;
-} rtx_pair;
-
 typedef struct loop_replace_args
 {
   rtx match;
@@ -247,8 +372,8 @@ typedef struct loop_replace_args
 } loop_replace_args;
 
 /* Nonzero iff INSN is between START and END, inclusive.  */
-#define INSN_IN_RANGE_P(INSN, START, END)      \
-  (INSN_UID (INSN) < max_uid_for_loop          \
+#define INSN_IN_RANGE_P(INSN, START, END)      \
+  (INSN_UID (INSN) < max_uid_for_loop          \
    && INSN_LUID (INSN) >= INSN_LUID (START)    \
    && INSN_LUID (INSN) <= INSN_LUID (END))
 
@@ -320,12 +445,11 @@ loop_optimize (f, dumpfile, flags)
      FILE *dumpfile;
      int flags;
 {
-  register rtx insn;
-  register int i;
+  rtx insn;
+  int i;
   struct loops loops_data;
   struct loops *loops = &loops_data;
   struct loop_info *loops_info;
-  static char *moved_once;
 
   loop_dump_stream = dumpfile;
 
@@ -352,8 +476,6 @@ loop_optimize (f, dumpfile, flags)
 
   loops->num = max_loop_num;
 
-  moved_once = (char *) xcalloc (max_reg_before_loop, sizeof (char));
-
   /* Get size to use for tables indexed by uids.
      Leave some space for labels allocated by find_and_verify_loops.  */
   max_uid_for_loop = get_max_uid () + 1 + max_loop_num * 32;
@@ -372,7 +494,7 @@ loop_optimize (f, dumpfile, flags)
 
   /* Allocate and initialize auxiliary loop information.  */
   loops_info = xcalloc (loops->num, sizeof (struct loop_info));
-  for (i = 0; i < loops->num; i++)
+  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
@@ -397,7 +519,7 @@ loop_optimize (f, dumpfile, flags)
   /* find_and_verify_loops has already called compute_luids, but it
      might have rearranged code afterwards, so we need to recompute
      the luids now.  */
-  max_luid = compute_luids (f, NULL_RTX, 0);
+  compute_luids (f, NULL_RTX, 0);
 
   /* Don't leave gaps in uid_luid for insns that have been
      deleted.  It is possible that the first or last insn
@@ -423,25 +545,14 @@ loop_optimize (f, dumpfile, flags)
   for (i = max_loop_num - 1; i >= 0; i--)
     {
       struct loop *loop = &loops->array[i];
-      struct loop_regs *regs = LOOP_REGS (loop);
-
-      regs->moved_once = moved_once;
 
       if (! loop->invalid && loop->end)
        scan_loop (loop, flags);
     }
 
-  /* If there were lexical blocks inside the loop, they have been
-     replicated.  We will now have more than one NOTE_INSN_BLOCK_BEG
-     and NOTE_INSN_BLOCK_END for each such block.  We must duplicate
-     the BLOCKs as well.  */
-  if (write_symbols != NO_DEBUG)
-    reorder_blocks ();
-
   end_alias_analysis ();
 
   /* Clean up.  */
-  free (moved_once);
   free (uid_luid);
   free (uid_loop);
   free (loops_info);
@@ -493,7 +604,7 @@ scan_loop (loop, flags)
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
-  register int i;
+  int i;
   rtx loop_start = loop->start;
   rtx loop_end = loop->end;
   rtx p;
@@ -502,8 +613,6 @@ scan_loop (loop, flags)
   /* 1 if we are scanning insns that might never be executed
      due to a subroutine call which might exit before they are reached.  */
   int call_passed = 0;
-  /* Jump insn that enters the loop, or 0 if control drops in.  */
-  rtx loop_entry_jump = 0;
   /* Number of insns in the loop.  */
   int insn_count;
   int tem;
@@ -519,13 +628,12 @@ scan_loop (loop, flags)
   int threshold;
   /* Nonzero if we are scanning instructions in a sub-loop.  */
   int loop_depth = 0;
-  int nregs;
+  int in_libcall;
 
   loop->top = 0;
 
   movables->head = 0;
   movables->last = 0;
-  movables->num = 0;
 
   /* Determine whether this loop starts with a jump down to a test at
      the end.  This will occur for a small number of loops with a test
@@ -554,6 +662,15 @@ scan_loop (loop, flags)
 
   loop->scan_start = p;
 
+  /* If loop end is the end of the current function, then emit a
+     NOTE_INSN_DELETED after loop_end and set loop->sink to the dummy
+     note insn.  This is the position we use when sinking insns out of
+     the loop.  */
+  if (NEXT_INSN (loop->end) != 0)
+    loop->sink = NEXT_INSN (loop->end);
+  else
+    loop->sink = emit_note_after (NOTE_INSN_DELETED, loop->end);
+
   /* Set up variables describing this loop.  */
   prescan_loop (loop);
   threshold = (loop_info->has_call ? 1 : 2) * (1 + n_non_fixed_regs);
@@ -563,24 +680,20 @@ scan_loop (loop, flags)
      Start scan from there.
      But record in LOOP->TOP the place where the end-test jumps
      back to so we can scan that after the end of the loop.  */
-  if (GET_CODE (p) == JUMP_INSN)
-    {
-      loop_entry_jump = p;
-
+  if (GET_CODE (p) == JUMP_INSN
       /* Loop entry must be unconditional jump (and not a RETURN)  */
-      if (any_uncondjump_p (p)
-         && JUMP_LABEL (p) != 0
-         /* Check to see whether the jump actually
-            jumps out of the loop (meaning it's no loop).
-            This case can happen for things like
-            do {..} while (0).  If this label was generated previously
-            by loop, we can't tell anything about it and have to reject
-            the loop.  */
-         && INSN_IN_RANGE_P (JUMP_LABEL (p), loop_start, loop_end))
-       {
-         loop->top = next_label (loop->scan_start);
-         loop->scan_start = JUMP_LABEL (p);
-       }
+      && any_uncondjump_p (p)
+      && JUMP_LABEL (p) != 0
+      /* Check to see whether the jump actually
+        jumps out of the loop (meaning it's no loop).
+        This case can happen for things like
+        do {..} while (0).  If this label was generated previously
+        by loop, we can't tell anything about it and have to reject
+        the loop.  */
+      && INSN_IN_RANGE_P (JUMP_LABEL (p), loop_start, loop_end))
+    {
+      loop->top = next_label (loop->scan_start);
+      loop->scan_start = JUMP_LABEL (p);
     }
 
   /* If LOOP->SCAN_START was an insn created by loop, we don't know its luid
@@ -600,43 +713,11 @@ scan_loop (loop, flags)
       return;
     }
 
-  /* Count number of times each reg is set during this loop.  Set
-     VARRAY_CHAR (regs->may_not_optimize, I) if it is not safe to move
-     out the setting of register I.  Set VARRAY_RTX
-     (regs->single_usage, I).  */
-
-  /* Allocate extra space for REGS that might be created by
-     load_mems.  We allocate a little extra slop as well, in the hopes
-     that even after the moving of movables creates some new registers
-     we won't have to reallocate these arrays.  However, we do grow
-     the arrays, if necessary, in load_mems_recount_loop_regs_set.  */
-  nregs = max_reg_num () + loop_info->mems_idx + 16;
-  VARRAY_INT_INIT (regs->set_in_loop, nregs, "set_in_loop");
-  VARRAY_INT_INIT (regs->n_times_set, nregs, "n_times_set");
-  VARRAY_CHAR_INIT (regs->may_not_optimize, nregs, "may_not_optimize");
-  VARRAY_RTX_INIT (regs->single_usage, nregs, "single_usage");
-
-  regs->num = nregs;
-
-  count_loop_regs_set (loop, regs->may_not_optimize, regs->single_usage,
-                      &insn_count, nregs);
-
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      VARRAY_CHAR (regs->may_not_optimize, i) = 1;
-      VARRAY_INT (regs->set_in_loop, i) = 1;
-    }
-
-#ifdef AVOID_CCMODE_COPIES
-  /* Don't try to move insns which set CC registers if we should not
-     create CCmode register copies.  */
-  for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
-    if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
-      VARRAY_CHAR (regs->may_not_optimize, i) = 1;
-#endif
-
-  bcopy ((char *) &regs->set_in_loop->data,
-        (char *) &regs->n_times_set->data, nregs * sizeof (int));
+  /* Allocate extra space for REGs that might be created by load_mems.
+     We allocate a little extra slop as well, in the hopes that we
+     won't have to reallocate the regs array.  */
+  loop_regs_scan (loop, loop_info->mems_idx + 16);
+  insn_count = count_insns_in_loop (loop);
 
   if (loop_dump_stream)
     {
@@ -648,7 +729,7 @@ scan_loop (loop, flags)
     }
 
   /* Scan through the loop finding insns that are safe to move.
-     Set regs->set_in_loop negative for the reg being set, so that
+     Set REGS->ARRAY[I].SET_IN_LOOP negative for the reg I being set, so that
      this reg will be considered invariant for subsequent insns.
      We consider whether subsequent insns use the reg
      in deciding whether it is worth actually moving.
@@ -660,294 +741,343 @@ scan_loop (loop, flags)
      When MAYBE_NEVER is 0, all insns will be executed at least once
      so that is not a problem.  */
 
-  for (p = next_insn_in_loop (loop, loop->scan_start);
+  for (in_libcall = 0, p = next_insn_in_loop (loop, loop->scan_start);
        p != NULL_RTX;
        p = next_insn_in_loop (loop, p))
     {
-      if (GET_CODE (p) == INSN
-         && (set = single_set (p))
-         && GET_CODE (SET_DEST (set)) == REG
-         && ! VARRAY_CHAR (regs->may_not_optimize, REGNO (SET_DEST (set))))
+      if (in_libcall && INSN_P (p) && find_reg_note (p, REG_RETVAL, NULL_RTX))
+       in_libcall--;
+      if (GET_CODE (p) == INSN)
        {
-         int tem1 = 0;
-         int tem2 = 0;
-         int move_insn = 0;
-         rtx src = SET_SRC (set);
-         rtx dependencies = 0;
-
-         /* Figure out what to use as a source of this insn.  If a REG_EQUIV
-            note is given or if a REG_EQUAL note with a constant operand is
-            specified, use it as the source and mark that we should move
-            this insn by calling emit_move_insn rather that duplicating the
-            insn.
-
-            Otherwise, only use the REG_EQUAL contents if a REG_RETVAL note
-            is present.  */
-         temp = find_reg_note (p, REG_EQUIV, NULL_RTX);
+         temp = find_reg_note (p, REG_LIBCALL, NULL_RTX);
          if (temp)
-           src = XEXP (temp, 0), move_insn = 1;
-         else
+           in_libcall++;
+         if (! in_libcall
+             && (set = single_set (p))
+             && GET_CODE (SET_DEST (set)) == REG
+#ifdef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
+             && SET_DEST (set) != pic_offset_table_rtx
+#endif
+             && ! regs->array[REGNO (SET_DEST (set))].may_not_optimize)
            {
-             temp = find_reg_note (p, REG_EQUAL, NULL_RTX);
-             if (temp && CONSTANT_P (XEXP (temp, 0)))
+             int tem1 = 0;
+             int tem2 = 0;
+             int move_insn = 0;
+             int insert_temp = 0;
+             rtx src = SET_SRC (set);
+             rtx dependencies = 0;
+
+             /* Figure out what to use as a source of this insn.  If a
+                REG_EQUIV note is given or if a REG_EQUAL note with a
+                constant operand is specified, use it as the source and
+                mark that we should move this insn by calling
+                emit_move_insn rather that duplicating the insn.
+
+                Otherwise, only use the REG_EQUAL contents if a REG_RETVAL
+                note is present.  */
+             temp = find_reg_note (p, REG_EQUIV, NULL_RTX);
+             if (temp)
                src = XEXP (temp, 0), move_insn = 1;
-             if (temp && find_reg_note (p, REG_RETVAL, NULL_RTX))
+             else
                {
-                 src = XEXP (temp, 0);
-                 /* A libcall block can use regs that don't appear in
-                    the equivalent expression.  To move the libcall,
-                    we must move those regs too.  */
-                 dependencies = libcall_other_reg (p, src);
+                 temp = find_reg_note (p, REG_EQUAL, NULL_RTX);
+                 if (temp && CONSTANT_P (XEXP (temp, 0)))
+                   src = XEXP (temp, 0), move_insn = 1;
+                 if (temp && find_reg_note (p, REG_RETVAL, NULL_RTX))
+                   {
+                     src = XEXP (temp, 0);
+                     /* A libcall block can use regs that don't appear in
+                        the equivalent expression.  To move the libcall,
+                        we must move those regs too.  */
+                     dependencies = libcall_other_reg (p, src);
+                   }
                }
-           }
 
-         /* Don't try to optimize a register that was made
-            by loop-optimization for an inner loop.
-            We don't know its life-span, so we can't compute the benefit.  */
-         if (REGNO (SET_DEST (set)) >= max_reg_before_loop)
-           ;
-         else if (/* The register is used in basic blocks other
+             /* For parallels, add any possible uses to the dependencies, as
+                we can't move the insn without resolving them first.  */
+             if (GET_CODE (PATTERN (p)) == PARALLEL)
+               {
+                 for (i = 0; i < XVECLEN (PATTERN (p), 0); i++)
+                   {
+                     rtx x = XVECEXP (PATTERN (p), 0, i);
+                     if (GET_CODE (x) == USE)
+                       dependencies
+                         = gen_rtx_EXPR_LIST (VOIDmode, XEXP (x, 0),
+                                              dependencies);
+                   }
+               }
+
+             if (/* The register is used in basic blocks other
                      than the one where it is set (meaning that
                      something after this point in the loop might
                      depend on its value before the set).  */
                   ! reg_in_basic_block_p (p, SET_DEST (set))
-                  /* And the set is not guaranteed to be executed one
+                  /* And the set is not guaranteed to be executed once
                      the loop starts, or the value before the set is
                      needed before the set occurs...
 
-                     ??? Note we have quadratic behaviour here, mitigated
+                     ??? Note we have quadratic behavior here, mitigated
                      by the fact that the previous test will often fail for
                      large loops.  Rather than re-scanning the entire loop
                      each time for register usage, we should build tables
                      of the register usage and use them here instead.  */
                   && (maybe_never
                       || loop_reg_used_before_p (loop, set, p)))
-           /* It is unsafe to move the set.
-
-              This code used to consider it OK to move a set of a variable
-              which was not created by the user and not used in an exit test.
-              That behavior is incorrect and was removed.  */
-           ;
-         else if ((tem = loop_invariant_p (loop, src))
-                  && (dependencies == 0
-                      || (tem2 = loop_invariant_p (loop, dependencies)) != 0)
-                  && (VARRAY_INT (regs->set_in_loop,
-                                  REGNO (SET_DEST (set))) == 1
-                      || (tem1
-                          = consec_sets_invariant_p
-                          (loop, SET_DEST (set),
-                           VARRAY_INT (regs->set_in_loop,
-                                       REGNO (SET_DEST (set))),
-                           p)))
-                  /* If the insn can cause a trap (such as divide by zero),
-                     can't move it unless it's guaranteed to be executed
-                     once loop is entered.  Even a function call might
-                     prevent the trap insn from being reached
-                     (since it might exit!)  */
-                  && ! ((maybe_never || call_passed)
-                        && may_trap_p (src)))
-           {
-             register struct movable *m;
-             register int regno = REGNO (SET_DEST (set));
-
-             /* A potential lossage is where we have a case where two insns
-                can be combined as long as they are both in the loop, but
-                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 (a "large loop"), see if
-                we can replace the usage of 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.  */
-
-             if (loop_info->has_call
-                 && VARRAY_RTX (regs->single_usage, regno) != 0
-                 && VARRAY_RTX (regs->single_usage, regno) != const0_rtx
-                 && REGNO_FIRST_UID (regno) == INSN_UID (p)
-                 && (REGNO_LAST_UID (regno)
-                     == INSN_UID (VARRAY_RTX (regs->single_usage, regno)))
-                 && VARRAY_INT (regs->set_in_loop, regno) == 1
-                 && ! side_effects_p (SET_SRC (set))
-                 && ! find_reg_note (p, REG_RETVAL, NULL_RTX)
-                 && (! SMALL_REGISTER_CLASSES
-                     || (! (GET_CODE (SET_SRC (set)) == REG
-                            && REGNO (SET_SRC (set)) < FIRST_PSEUDO_REGISTER)))
-                 /* 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,
-                                          VARRAY_RTX
-                                          (regs->single_usage, regno))
-                 && no_labels_between_p (p, VARRAY_RTX (regs->single_usage,
-                                                        regno))
-                 && validate_replace_rtx (SET_DEST (set), SET_SRC (set),
-                                          VARRAY_RTX
-                                          (regs->single_usage, regno)))
-               {
-                 /* 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 (VARRAY_RTX (regs->single_usage, regno))
-                   = replace_rtx (REG_NOTES (VARRAY_RTX
-                                             (regs->single_usage, regno)),
-                                  SET_DEST (set), copy_rtx (SET_SRC (set)));
-
-                 PUT_CODE (p, NOTE);
-                 NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED;
-                 NOTE_SOURCE_FILE (p) = 0;
-                 VARRAY_INT (regs->set_in_loop, regno) = 0;
-                 continue;
-               }
-
-             m = (struct movable *) xmalloc (sizeof (struct movable));
-             m->next = 0;
-             m->insn = p;
-             m->set_src = src;
-             m->dependencies = dependencies;
-             m->set_dest = SET_DEST (set);
-             m->force = 0;
-             m->consec = VARRAY_INT (regs->set_in_loop,
-                                     REGNO (SET_DEST (set))) - 1;
-             m->done = 0;
-             m->forces = 0;
-             m->partial = 0;
-             m->move_insn = move_insn;
-             m->move_insn_first = 0;
-             m->is_equiv = (find_reg_note (p, REG_EQUIV, NULL_RTX) != 0);
-             m->savemode = VOIDmode;
-             m->regno = regno;
-             /* Set M->cond if either loop_invariant_p
-                or consec_sets_invariant_p returned 2
-                (only conditionally invariant).  */
-             m->cond = ((tem | tem1 | tem2) > 1);
-             m->global = (REGNO_LAST_LUID (regno)
-                          > INSN_LUID (loop_end)
-                          || REGNO_FIRST_LUID (regno) < INSN_LUID (loop_start));
-             m->match = 0;
-             m->lifetime = (REGNO_LAST_LUID (regno)
-                            - REGNO_FIRST_LUID (regno));
-             m->savings = VARRAY_INT (regs->n_times_set, regno);
-             if (find_reg_note (p, REG_RETVAL, NULL_RTX))
-               m->savings += libcall_benefit (p);
-             VARRAY_INT (regs->set_in_loop, regno) = move_insn ? -2 : -1;
-             /* Add M to the end of the chain MOVABLES.  */
-             loop_movables_add (movables, m);
-
-             if (m->consec > 0)
+               /* It is unsafe to move the set.  However, it may be OK to
+                  move the source into a new pseudo, and substitute a 
+                  reg-to-reg copy for the original insn.
+
+                  This code used to consider it OK to move a set of a variable
+                  which was not created by the user and not used in an exit
+                  test.
+                  That behavior is incorrect and was removed.  */
+               insert_temp = 1;
+
+             /* Don't try to optimize a MODE_CC set with a constant
+                source.  It probably will be combined with a conditional
+                jump.  */
+             if (GET_MODE_CLASS (GET_MODE (SET_DEST (set))) == MODE_CC
+                 && CONSTANT_P (src))
+               ;
+             /* Don't try to optimize a register that was made
+                by loop-optimization for an inner loop.
+                We don't know its life-span, so we can't compute
+                the benefit.  */
+             else if (REGNO (SET_DEST (set)) >= max_reg_before_loop)
+               ;
+             /* Don't move the source and add a reg-to-reg copy:
+                - 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).  */
+             else if (insert_temp 
+                      && (optimize_size
+                          || ! can_copy_p (GET_MODE (SET_SRC (set)))
+                          || GET_CODE (SET_SRC (set)) == REG
+                          || (CONSTANT_P (SET_SRC (set))
+                              && LEGITIMATE_CONSTANT_P (SET_SRC (set)))))
+               ;
+             else if ((tem = loop_invariant_p (loop, src))
+                      && (dependencies == 0
+                          || (tem2
+                              = loop_invariant_p (loop, dependencies)) != 0)
+                      && (regs->array[REGNO (SET_DEST (set))].set_in_loop == 1
+                          || (tem1
+                              = consec_sets_invariant_p
+                              (loop, SET_DEST (set),
+                               regs->array[REGNO (SET_DEST (set))].set_in_loop,
+                               p)))
+                      /* If the insn can cause a trap (such as divide by zero),
+                         can't move it unless it's guaranteed to be executed
+                         once loop is entered.  Even a function call might
+                         prevent the trap insn from being reached
+                         (since it might exit!)  */
+                      && ! ((maybe_never || call_passed)
+                            && may_trap_p (src)))
                {
-                 /* It is possible for the first instruction to have a
-                    REG_EQUAL note but a non-invariant SET_SRC, so we must
-                    remember the status of the first instruction in case
-                    the last instruction doesn't have a REG_EQUAL note.  */
-                 m->move_insn_first = m->move_insn;
-
-                 /* Skip this insn, not checking REG_LIBCALL notes.  */
-                 p = next_nonnote_insn (p);
-                 /* Skip the consecutive insns, if there are any.  */
-                 p = skip_consec_insns (p, m->consec);
-                 /* Back up to the last insn of the consecutive group.  */
-                 p = prev_nonnote_insn (p);
-
-                 /* We must now reset m->move_insn, m->is_equiv, and possibly
-                    m->set_src to correspond to the effects of all the
-                    insns.  */
-                 temp = find_reg_note (p, REG_EQUIV, NULL_RTX);
-                 if (temp)
-                   m->set_src = XEXP (temp, 0), m->move_insn = 1;
-                 else
+                 struct movable *m;
+                 int regno = REGNO (SET_DEST (set));
+
+                 /* A potential lossage is where we have a case where two insns
+                    can be combined as long as they are both in the loop, but
+                    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
+                    (a "large loop"), see if we can replace the usage of
+                    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.  */
+
+                 if (loop_info->has_call
+                     && regs->array[regno].single_usage != 0
+                     && regs->array[regno].single_usage != const0_rtx
+                     && REGNO_FIRST_UID (regno) == INSN_UID (p)
+                     && (REGNO_LAST_UID (regno)
+                         == INSN_UID (regs->array[regno].single_usage))
+                     && regs->array[regno].set_in_loop == 1
+                     && GET_CODE (SET_SRC (set)) != ASM_OPERANDS
+                     && ! side_effects_p (SET_SRC (set))
+                     && ! find_reg_note (p, REG_RETVAL, NULL_RTX)
+                     && (! SMALL_REGISTER_CLASSES
+                         || (! (GET_CODE (SET_SRC (set)) == REG
+                                && (REGNO (SET_SRC (set))
+                                    < FIRST_PSEUDO_REGISTER))))
+                     /* 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))
                    {
-                     temp = find_reg_note (p, REG_EQUAL, NULL_RTX);
-                     if (temp && CONSTANT_P (XEXP (temp, 0)))
-                       m->set_src = XEXP (temp, 0), m->move_insn = 1;
-                     else
-                       m->move_insn = 0;
+                     /* 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))));
 
+                     delete_insn (p);
+                     for (i = 0; i < LOOP_REGNO_NREGS (regno, SET_DEST (set));
+                          i++)
+                       regs->array[regno+i].set_in_loop = 0;
+                     continue;
                    }
-                 m->is_equiv = (find_reg_note (p, REG_EQUIV, NULL_RTX) != 0);
-               }
-           }
-         /* If this register is always set within a STRICT_LOW_PART
-            or set to zero, then its high bytes are constant.
-            So clear them outside the loop and within the loop
-            just load the low bytes.
-            We must check that the machine has an instruction to do so.
-            Also, if the value loaded into the register
-            depends on the same register, this cannot be done.  */
-         else if (SET_SRC (set) == const0_rtx
-                  && GET_CODE (NEXT_INSN (p)) == INSN
-                  && (set1 = single_set (NEXT_INSN (p)))
-                  && GET_CODE (set1) == SET
-                  && (GET_CODE (SET_DEST (set1)) == STRICT_LOW_PART)
-                  && (GET_CODE (XEXP (SET_DEST (set1), 0)) == SUBREG)
-                  && (SUBREG_REG (XEXP (SET_DEST (set1), 0))
-                      == SET_DEST (set))
-                  && !reg_mentioned_p (SET_DEST (set), SET_SRC (set1)))
-           {
-             register int regno = REGNO (SET_DEST (set));
-             if (VARRAY_INT (regs->set_in_loop, regno) == 2)
-               {
-                 register struct movable *m;
-                 m = (struct movable *) alloca (sizeof (struct movable));
+
+                 m = (struct movable *) xmalloc (sizeof (struct movable));
                  m->next = 0;
                  m->insn = p;
+                 m->set_src = src;
+                 m->dependencies = dependencies;
                  m->set_dest = SET_DEST (set);
-                 m->dependencies = 0;
                  m->force = 0;
-                 m->consec = 0;
+                 m->consec
+                   = regs->array[REGNO (SET_DEST (set))].set_in_loop - 1;
                  m->done = 0;
                  m->forces = 0;
-                 m->move_insn = 0;
+                 m->partial = 0;
+                 m->move_insn = move_insn;
                  m->move_insn_first = 0;
-                 m->partial = 1;
-                 /* If the insn may not be executed on some cycles,
-                    we can't clear the whole reg; clear just high part.
-                    Not even if the reg is used only within this loop.
-                    Consider this:
-                    while (1)
-                      while (s != t) {
-                        if (foo ()) x = *s;
-                        use (x);
-                      }
-                    Clearing x before the inner loop could clobber a value
-                    being saved from the last time around the outer loop.
-                    However, if the reg is not used outside this loop
-                    and all uses of the register are in the same
-                    basic block as the store, there is no problem.
-
-                    If this insn was made by loop, we don't know its
-                    INSN_LUID and hence must make a conservative
-                    assumption.  */
-                 m->global = (INSN_UID (p) >= max_uid_for_loop
-                              || (REGNO_LAST_LUID (regno)
-                                  > INSN_LUID (loop_end))
-                              || (REGNO_FIRST_LUID (regno)
-                                  < INSN_LUID (p))
-                              || (labels_in_range_p
-                                  (p, REGNO_FIRST_LUID (regno))));
-                 if (maybe_never && m->global)
-                   m->savemode = GET_MODE (SET_SRC (set1));
-                 else
-                   m->savemode = VOIDmode;
+                 m->insert_temp = insert_temp;
+                 m->is_equiv = (find_reg_note (p, REG_EQUIV, NULL_RTX) != 0);
+                 m->savemode = VOIDmode;
                  m->regno = regno;
-                 m->cond = 0;
+                 /* Set M->cond if either loop_invariant_p
+                    or consec_sets_invariant_p returned 2
+                    (only conditionally invariant).  */
+                 m->cond = ((tem | tem1 | tem2) > 1);
+                 m->global =  LOOP_REG_GLOBAL_P (loop, regno);
                  m->match = 0;
-                 m->lifetime = (REGNO_LAST_LUID (regno)
-                                - REGNO_FIRST_LUID (regno));
-                 m->savings = 1;
-                 VARRAY_INT (regs->set_in_loop, regno) = -1;
+                 m->lifetime = LOOP_REG_LIFETIME (loop, regno);
+                 m->savings = regs->array[regno].n_times_set;
+                 if (find_reg_note (p, REG_RETVAL, NULL_RTX))
+                   m->savings += libcall_benefit (p);
+                 for (i = 0; i < LOOP_REGNO_NREGS (regno, SET_DEST (set)); i++)
+                   regs->array[regno+i].set_in_loop = move_insn ? -2 : -1;
                  /* Add M to the end of the chain MOVABLES.  */
                  loop_movables_add (movables, m);
+
+                 if (m->consec > 0)
+                   {
+                     /* It is possible for the first instruction to have a
+                        REG_EQUAL note but a non-invariant SET_SRC, so we must
+                        remember the status of the first instruction in case
+                        the last instruction doesn't have a REG_EQUAL note.  */
+                     m->move_insn_first = m->move_insn;
+
+                     /* Skip this insn, not checking REG_LIBCALL notes.  */
+                     p = next_nonnote_insn (p);
+                     /* Skip the consecutive insns, if there are any.  */
+                     p = skip_consec_insns (p, m->consec);
+                     /* Back up to the last insn of the consecutive group.  */
+                     p = prev_nonnote_insn (p);
+
+                     /* We must now reset m->move_insn, m->is_equiv, and
+                        possibly m->set_src to correspond to the effects of
+                        all the insns.  */
+                     temp = find_reg_note (p, REG_EQUIV, NULL_RTX);
+                     if (temp)
+                       m->set_src = XEXP (temp, 0), m->move_insn = 1;
+                     else
+                       {
+                         temp = find_reg_note (p, REG_EQUAL, NULL_RTX);
+                         if (temp && CONSTANT_P (XEXP (temp, 0)))
+                           m->set_src = XEXP (temp, 0), m->move_insn = 1;
+                         else
+                           m->move_insn = 0;
+
+                       }
+                     m->is_equiv
+                       = (find_reg_note (p, REG_EQUIV, NULL_RTX) != 0);
+                   }
+               }
+             /* If this register is always set within a STRICT_LOW_PART
+                or set to zero, then its high bytes are constant.
+                So clear them outside the loop and within the loop
+                just load the low bytes.
+                We must check that the machine has an instruction to do so.
+                Also, if the value loaded into the register
+                depends on the same register, this cannot be done.  */
+             else if (SET_SRC (set) == const0_rtx
+                      && GET_CODE (NEXT_INSN (p)) == INSN
+                      && (set1 = single_set (NEXT_INSN (p)))
+                      && GET_CODE (set1) == SET
+                      && (GET_CODE (SET_DEST (set1)) == STRICT_LOW_PART)
+                      && (GET_CODE (XEXP (SET_DEST (set1), 0)) == SUBREG)
+                      && (SUBREG_REG (XEXP (SET_DEST (set1), 0))
+                          == SET_DEST (set))
+                      && !reg_mentioned_p (SET_DEST (set), SET_SRC (set1)))
+               {
+                 int regno = REGNO (SET_DEST (set));
+                 if (regs->array[regno].set_in_loop == 2)
+                   {
+                     struct movable *m;
+                     m = (struct movable *) xmalloc (sizeof (struct movable));
+                     m->next = 0;
+                     m->insn = p;
+                     m->set_dest = SET_DEST (set);
+                     m->dependencies = 0;
+                     m->force = 0;
+                     m->consec = 0;
+                     m->done = 0;
+                     m->forces = 0;
+                     m->move_insn = 0;
+                     m->move_insn_first = 0;
+                     m->insert_temp = insert_temp;
+                     m->partial = 1;
+                     /* If the insn may not be executed on some cycles,
+                        we can't clear the whole reg; clear just high part.
+                        Not even if the reg is used only within this loop.
+                        Consider this:
+                        while (1)
+                          while (s != t) {
+                            if (foo ()) x = *s;
+                            use (x);
+                          }
+                        Clearing x before the inner loop could clobber a value
+                        being saved from the last time around the outer loop.
+                        However, if the reg is not used outside this loop
+                        and all uses of the register are in the same
+                        basic block as the store, there is no problem.
+
+                        If this insn was made by loop, we don't know its
+                        INSN_LUID and hence must make a conservative
+                        assumption.  */
+                     m->global = (INSN_UID (p) >= max_uid_for_loop
+                                  || LOOP_REG_GLOBAL_P (loop, regno)
+                                  || (labels_in_range_p
+                                      (p, REGNO_FIRST_LUID (regno))));
+                     if (maybe_never && m->global)
+                       m->savemode = GET_MODE (SET_SRC (set1));
+                     else
+                       m->savemode = VOIDmode;
+                     m->regno = regno;
+                     m->cond = 0;
+                     m->match = 0;
+                     m->lifetime = LOOP_REG_LIFETIME (loop, regno);
+                     m->savings = 1;
+                     for (i = 0;
+                          i < LOOP_REGNO_NREGS (regno, SET_DEST (set));
+                          i++)
+                       regs->array[regno+i].set_in_loop = -1;
+                     /* Add M to the end of the chain MOVABLES.  */
+                     loop_movables_add (movables, m);
+                   }
                }
            }
        }
       /* Past a call insn, we get to insns which might not be executed
         because the call might exit.  This matters for insns that trap.
         Constant and pure call insns always return, so they don't count.  */
-      else if (GET_CODE (p) == CALL_INSN && ! CONST_CALL_P (p))
+      else if (GET_CODE (p) == CALL_INSN && ! CONST_OR_PURE_CALL_P (p))
        call_passed = 1;
       /* Past a label or a jump, we get to insns for which we
         can't count on whether or how many times they will be
@@ -960,8 +1090,8 @@ scan_loop (loop, flags)
                  beginning, don't set maybe_never for that.  This must be an
                  unconditional jump, otherwise the code at the top of the
                  loop might never be executed.  Unconditional jumps are
-                 followed a by barrier then loop end.  */
-               && ! (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == loop->top
+                 followed by a barrier then the loop_end.  */
+              && ! (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == loop->top
                     && NEXT_INSN (NEXT_INSN (p)) == loop_end
                     && any_uncondjump_p (p)))
        maybe_never = 1;
@@ -998,24 +1128,48 @@ scan_loop (loop, flags)
   combine_movables (movables, regs);
 
   /* Now consider each movable insn to decide whether it is worth moving.
-     Store 0 in regs->set_in_loop for each reg that is moved.
+     Store 0 in regs->array[I].set_in_loop for each reg I that is moved.
 
-     Generally this increases code size, so do not move moveables when
-     optimizing for code size.  */
+     For machines with few registers this increases code size, so do not
+     move moveables when optimizing for code size on such machines.  
+     (The 18 below is the value for i386.)  */
 
-  if (! optimize_size)
-    move_movables (loop, movables, threshold, insn_count);
+  if (!optimize_size 
+      || (reg_class_size[GENERAL_REGS] > 18 && !loop_info->has_call))
+    {
+      move_movables (loop, movables, threshold, insn_count);
+
+      /* Recalculate regs->array if move_movables has created new
+        registers.  */
+      if (max_reg_num () > regs->num)
+       {
+         loop_regs_scan (loop, 0);
+         for (update_start = loop_start;
+              PREV_INSN (update_start)
+              && GET_CODE (PREV_INSN (update_start)) != CODE_LABEL;
+              update_start = PREV_INSN (update_start))
+           ;
+         update_end = NEXT_INSN (loop_end);
+
+         reg_scan_update (update_start, update_end, loop_max_reg);
+         loop_max_reg = max_reg_num ();
+       }
+    }
 
   /* Now candidates that still are negative are those not moved.
-     Change regs->set_in_loop to indicate that those are not actually
+     Change regs->array[I].set_in_loop to indicate that those are not actually
      invariant.  */
-  for (i = 0; i < nregs; i++)
-    if (VARRAY_INT (regs->set_in_loop, i) < 0)
-      VARRAY_INT (regs->set_in_loop, i) = VARRAY_INT (regs->n_times_set, i);
+  for (i = 0; i < regs->num; i++)
+    if (regs->array[i].set_in_loop < 0)
+      regs->array[i].set_in_loop = regs->array[i].n_times_set;
 
   /* Now that we've moved some things out of the loop, we might be able to
      hoist even more memory references.  */
-  load_mems_and_recount_loop_regs_set (loop, &insn_count);
+  load_mems (loop);
+
+  /* Recalculate regs->array if load_mems has created new registers.  */
+  if (max_reg_num () > regs->num)
+    loop_regs_scan (loop, 0);
 
   for (update_start = loop_start;
        PREV_INSN (update_start)
@@ -1033,24 +1187,23 @@ scan_loop (loop, flags)
        /* Ensure our label doesn't go away.  */
        LABEL_NUSES (update_end)++;
 
-      strength_reduce (loop, insn_count, flags);
+      strength_reduce (loop, flags);
 
       reg_scan_update (update_start, update_end, loop_max_reg);
       loop_max_reg = max_reg_num ();
 
       if (update_end && GET_CODE (update_end) == CODE_LABEL
          && --LABEL_NUSES (update_end) == 0)
-       delete_insn (update_end);
+       delete_related_insns (update_end);
     }
 
 
   /* The movable information is required for strength reduction.  */
   loop_movables_free (movables);
 
-  VARRAY_FREE (regs->single_usage);
-  VARRAY_FREE (regs->set_in_loop);
-  VARRAY_FREE (regs->n_times_set);
-  VARRAY_FREE (regs->may_not_optimize);
+  free (regs->array);
+  regs->array = 0;
+  regs->num = 0;
 }
 \f
 /* Add elements to *OUTPUT to record all the pseudo-regs
@@ -1248,7 +1401,7 @@ static void
 ignore_some_movables (movables)
      struct loop_movables *movables;
 {
-  register struct movable *m, *m1;
+  struct movable *m, *m1;
 
   for (m = movables->head; m; m = m->next)
     {
@@ -1280,7 +1433,8 @@ static void
 force_movables (movables)
      struct loop_movables *movables;
 {
-  register struct movable *m, *m1;
+  struct movable *m, *m1;
+
   for (m1 = movables->head; m1; m1 = m1->next)
     /* Omit this if moving just the (SET (REG) 0) of a zero-extend.  */
     if (!m1->partial && !m1->done)
@@ -1320,19 +1474,23 @@ combine_movables (movables, regs)
      struct loop_movables *movables;
      struct loop_regs *regs;
 {
-  register struct movable *m;
+  struct movable *m;
   char *matched_regs = (char *) xmalloc (regs->num);
   enum machine_mode mode;
 
   /* Regs that are set more than once are not allowed to match
      or be matched.  I'm no longer sure why not.  */
+  /* Only pseudo registers are allowed to match or be matched,
+     since move_movables does not validate the change.  */
   /* Perhaps testing m->consec_sets would be more appropriate here?  */
 
   for (m = movables->head; m; m = m->next)
-    if (m->match == 0 && VARRAY_INT (regs->n_times_set, m->regno) == 1
+    if (m->match == 0 && regs->array[m->regno].n_times_set == 1
+       && m->regno >= FIRST_PSEUDO_REGISTER
+       && !m->insert_temp
        && !m->partial)
       {
-       register struct movable *m1;
+       struct movable *m1;
        int regno = m->regno;
 
        memset (matched_regs, 0, regs->num);
@@ -1341,8 +1499,10 @@ combine_movables (movables, regs)
        /* We want later insns to match the first one.  Don't make the first
           one match any later ones.  So start this loop at m->next.  */
        for (m1 = m->next; m1; m1 = m1->next)
-         if (m != m1 && m1->match == 0 && VARRAY_INT (regs->n_times_set,
-                                                      m1->regno) == 1
+         if (m != m1 && m1->match == 0
+             && !m1->insert_temp
+             && regs->array[m1->regno].n_times_set == 1
+             && m1->regno >= FIRST_PSEUDO_REGISTER
              /* A reg used outside the loop mustn't be eliminated.  */
              && !m1->global
              /* A reg used for zero-extending mustn't be eliminated.  */
@@ -1385,7 +1545,7 @@ combine_movables (movables, regs)
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
-      register struct movable *m0 = 0;
+      struct movable *m0 = 0;
 
       /* Combine all the registers for extension from mode MODE.
         Don't combine any that are used outside this loop.  */
@@ -1393,7 +1553,8 @@ combine_movables (movables, regs)
        if (m->partial && ! m->global
            && mode == GET_MODE (SET_SRC (PATTERN (NEXT_INSN (m->insn)))))
          {
-           register struct movable *m1;
+           struct movable *m1;
+
            int first = REGNO_FIRST_LUID (m->regno);
            int last = REGNO_LAST_LUID (m->regno);
 
@@ -1431,6 +1592,24 @@ combine_movables (movables, regs)
   /* Clean up.  */
   free (matched_regs);
 }
+
+/* Returns the number of movable instructions in LOOP that were not
+   moved outside the loop.  */
+
+static int
+num_unmoved_movables (loop)
+     const struct loop *loop;
+{
+  int num = 0;
+  struct movable *m;
+
+  for (m = LOOP_MOVABLES (loop)->head; m; m = m->next)
+    if (!m->done)
+      ++num;
+
+  return num;
+}
+
 \f
 /* Return 1 if regs X and Y will become the same if moved.  */
 
@@ -1469,11 +1648,11 @@ rtx_equal_for_loop_p (x, y, movables, regs)
      struct loop_movables *movables;
      struct loop_regs *regs;
 {
-  register int i;
-  register int j;
-  register struct movable *m;
-  register enum rtx_code code;
-  register const char *fmt;
+  int i;
+  int j;
+  struct movable *m;
+  enum rtx_code code;
+  const char *fmt;
 
   if (x == y)
     return 1;
@@ -1484,7 +1663,7 @@ rtx_equal_for_loop_p (x, y, movables, regs)
 
   /* If we have a register and a constant, they may sometimes be
      equal.  */
-  if (GET_CODE (x) == REG && VARRAY_INT (regs->set_in_loop, REGNO (x)) == -2
+  if (GET_CODE (x) == REG && regs->array[REGNO (x)].set_in_loop == -2
       && CONSTANT_P (y))
     {
       for (m = movables->head; m; m = m->next)
@@ -1492,8 +1671,7 @@ rtx_equal_for_loop_p (x, y, movables, regs)
            && rtx_equal_p (m->set_src, y))
          return 1;
     }
-  else if (GET_CODE (y) == REG && VARRAY_INT (regs->set_in_loop,
-                                             REGNO (y)) == -2
+  else if (GET_CODE (y) == REG && regs->array[REGNO (y)].set_in_loop == -2
           && CONSTANT_P (x))
     {
       for (m = movables->head; m; m = m->next)
@@ -1580,7 +1758,8 @@ rtx_equal_for_loop_p (x, y, movables, regs)
 }
 \f
 /* If X contains any LABEL_REF's, add REG_LABEL notes for them to all
-  insns in INSNS which use the reference.  */
+   insns in INSNS which use the reference.  LABEL_NUSES for CODE_LABEL
+   references is incremented once for each added note.  */
 
 static void
 add_label_notes (x, insns)
@@ -1601,8 +1780,12 @@ add_label_notes (x, insns)
          mark_jump_label for additional information).  */
       for (insn = insns; insn; insn = NEXT_INSN (insn))
        if (reg_mentioned_p (XEXP (x, 0), insn))
-         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL, XEXP (x, 0),
-                                               REG_NOTES (insn));
+         {
+           REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0),
+                                                 REG_NOTES (insn));
+           if (LABEL_P (XEXP (x, 0)))
+             LABEL_NUSES (XEXP (x, 0))++;
+         }
     }
 
   fmt = GET_RTX_FORMAT (code);
@@ -1630,8 +1813,8 @@ move_movables (loop, movables, threshold, insn_count)
   struct loop_regs *regs = LOOP_REGS (loop);
   int nregs = regs->num;
   rtx new_start = 0;
-  register struct movable *m;
-  register rtx p;
+  struct movable *m;
+  rtx p;
   rtx loop_start = loop->start;
   rtx loop_end = loop->end;
   /* Map of pseudo-register replacements to handle combining
@@ -1640,8 +1823,6 @@ move_movables (loop, movables, threshold, insn_count)
   rtx *reg_map = (rtx *) xcalloc (nregs, sizeof (rtx));
   char *already_moved = (char *) xcalloc (nregs, sizeof (char));
 
-  movables->num = 0;
-
   for (m = movables->head; m; m = m->next)
     {
       /* Describe this movable insn.  */
@@ -1670,9 +1851,6 @@ move_movables (loop, movables, threshold, insn_count)
                     INSN_UID (m->forces->insn));
        }
 
-      /* Count movables.  Value used in heuristics in strength_reduce.  */
-      movables->num++;
-
       /* Ignore the insn if it's already done (it matched something else).
         Otherwise, see if it is now safe to move.  */
 
@@ -1687,8 +1865,8 @@ move_movables (loop, movables, threshold, insn_count)
                                                       m->insn))))
          && (! m->forces || m->forces->done))
        {
-         register int regno;
-         register rtx p;
+         int regno;
+         rtx p;
          int savings = m->savings;
 
          /* We have an insn that is safe to move.
@@ -1700,7 +1878,7 @@ move_movables (loop, movables, threshold, insn_count)
          if (loop_dump_stream)
            fprintf (loop_dump_stream, "savings %d ", savings);
 
-         if (regs->moved_once[regno] && loop_dump_stream)
+         if (regs->array[regno].moved_once && loop_dump_stream)
            fprintf (loop_dump_stream, "halved since already moved ");
 
          /* An insn MUST be moved if we already moved something else
@@ -1719,13 +1897,17 @@ move_movables (loop, movables, threshold, insn_count)
          if (already_moved[regno]
              || flag_move_all_movables
              || (threshold * savings * m->lifetime) >=
-                (regs->moved_once[regno] ? insn_count * 2 : insn_count)
+                (regs->array[regno].moved_once ? insn_count * 2 : insn_count)
              || (m->forces && m->forces->done
-                 && VARRAY_INT (regs->n_times_set, m->forces->regno) == 1))
+                 && regs->array[m->forces->regno].n_times_set == 1))
            {
              int count;
-             register struct movable *m1;
+             struct movable *m1;
              rtx first = NULL_RTX;
+             rtx newreg = NULL_RTX;
+
+             if (m->insert_temp)
+               newreg = gen_reg_rtx (GET_MODE (m->set_dest));
 
              /* Now move the insns that set the reg.  */
 
@@ -1740,7 +1922,7 @@ move_movables (loop, movables, threshold, insn_count)
                  for (m1 = m; m1->match; m1 = m1->match);
                  newpat = gen_move_insn (SET_DEST (PATTERN (m->insn)),
                                          SET_DEST (PATTERN (m1->insn)));
-                 i1 = emit_insn_before (newpat, loop_start);
+                 i1 = loop_insn_hoist (loop, newpat);
 
                  /* Mark the moved, invariant reg as being allowed to
                     share a hard reg with the other matching invariant.  */
@@ -1764,15 +1946,15 @@ move_movables (loop, movables, threshold, insn_count)
                 the move insn before the loop.  */
              else if (m->move_insn)
                {
-                 rtx i1, temp;
+                 rtx i1, temp, seq;
 
                  for (count = m->consec; count >= 0; count--)
                    {
                      /* If this is the first insn of a library call sequence,
-                        skip to the end.  */
+                        something is very wrong.  */
                      if (GET_CODE (p) != NOTE
                          && (temp = find_reg_note (p, REG_LIBCALL, NULL_RTX)))
-                       p = XEXP (temp, 0);
+                       abort ();
 
                      /* If this is the last insn of a libcall sequence, then
                         delete every insn in the sequence except the last.
@@ -1796,20 +1978,32 @@ move_movables (loop, movables, threshold, insn_count)
                         insn stream.  */
                      while (p && GET_CODE (p) == NOTE)
                        p = NEXT_INSN (temp) = NEXT_INSN (p);
+
+                     if (m->insert_temp)
+                       {
+                         /* Replace the original insn with a move from
+                            our newly created temp.  */
+                         start_sequence ();
+                         emit_move_insn (m->set_dest, newreg);
+                         seq = get_insns ();
+                         end_sequence ();
+                         emit_insn_before (seq, p);
+                       }
                    }
 
                  start_sequence ();
-                 emit_move_insn (m->set_dest, m->set_src);
-                 temp = get_insns ();
+                 emit_move_insn (m->insert_temp ? newreg : m->set_dest, 
+                                 m->set_src);
+                 seq = get_insns ();
                  end_sequence ();
 
-                 add_label_notes (m->set_src, temp);
+                 add_label_notes (m->set_src, seq);
 
-                 i1 = emit_insns_before (temp, loop_start);
+                 i1 = loop_insn_hoist (loop, seq);
                  if (! find_reg_note (i1, REG_EQUAL, NULL_RTX))
-                   REG_NOTES (i1)
-                     = gen_rtx_EXPR_LIST (m->is_equiv ? REG_EQUIV : REG_EQUAL,
-                                          m->set_src, REG_NOTES (i1));
+                   set_unique_reg_note (i1,
+                                        m->is_equiv ? REG_EQUIV : REG_EQUAL,
+                                        m->set_src);
 
                  if (loop_dump_stream)
                    fprintf (loop_dump_stream, " moved to %d", INSN_UID (i1));
@@ -1891,13 +2085,13 @@ move_movables (loop, movables, threshold, insn_count)
                              if (GET_CODE (temp) == CALL_INSN
                                  && fn_address != 0
                                  && reg_referenced_p (fn_reg, body))
-                               emit_insn_after (gen_move_insn (fn_reg,
-                                                               fn_address),
-                                                fn_address_insn);
+                               loop_insn_emit_after (loop, 0, fn_address_insn,
+                                                     gen_move_insn
+                                                     (fn_reg, fn_address));
 
                              if (GET_CODE (temp) == CALL_INSN)
                                {
-                                 i1 = emit_call_insn_before (body, loop_start);
+                                 i1 = loop_call_insn_hoist (loop, body);
                                  /* Because the USAGE information potentially
                                     contains objects other than hard registers
                                     we need to copy it.  */
@@ -1906,12 +2100,13 @@ move_movables (loop, movables, threshold, insn_count)
                                      = copy_rtx (CALL_INSN_FUNCTION_USAGE (temp));
                                }
                              else
-                               i1 = emit_insn_before (body, loop_start);
+                               i1 = loop_insn_hoist (loop, body);
                              if (first == 0)
                                first = i1;
                              if (temp == fn_address_insn)
                                fn_address_insn = i1;
                              REG_NOTES (i1) = REG_NOTES (temp);
+                             REG_NOTES (temp) = NULL;
                              delete_insn (temp);
                            }
                          if (new_start == 0)
@@ -1927,8 +2122,8 @@ move_movables (loop, movables, threshold, insn_count)
                          rtx tem;
 
                          start_sequence ();
-                         tem = expand_binop
-                           (GET_MODE (reg), and_optab, reg,
+                         tem = expand_simple_binop
+                           (GET_MODE (reg), AND, reg,
                             GEN_INT ((((HOST_WIDE_INT) 1
                                        << GET_MODE_BITSIZE (m->savemode)))
                                      - 1),
@@ -1937,13 +2132,13 @@ move_movables (loop, movables, threshold, insn_count)
                            abort ();
                          if (tem != reg)
                            emit_move_insn (reg, tem);
-                         sequence = gen_sequence ();
+                         sequence = get_insns ();
                          end_sequence ();
-                         i1 = emit_insn_before (sequence, loop_start);
+                         i1 = loop_insn_hoist (loop, sequence);
                        }
                      else if (GET_CODE (p) == CALL_INSN)
                        {
-                         i1 = emit_call_insn_before (PATTERN (p), loop_start);
+                         i1 = loop_call_insn_hoist (loop, PATTERN (p));
                          /* Because the USAGE information potentially
                             contains objects other than hard registers
                             we need to copy it.  */
@@ -1953,28 +2148,38 @@ move_movables (loop, movables, threshold, insn_count)
                        }
                      else if (count == m->consec && m->move_insn_first)
                        {
+                         rtx seq;
                          /* The SET_SRC might not be invariant, so we must
                             use the REG_EQUAL note.  */
                          start_sequence ();
                          emit_move_insn (m->set_dest, m->set_src);
-                         temp = get_insns ();
+                         seq = get_insns ();
                          end_sequence ();
 
-                         add_label_notes (m->set_src, temp);
+                         add_label_notes (m->set_src, seq);
 
-                         i1 = emit_insns_before (temp, loop_start);
+                         i1 = loop_insn_hoist (loop, seq);
                          if (! find_reg_note (i1, REG_EQUAL, NULL_RTX))
-                           REG_NOTES (i1)
-                             = gen_rtx_EXPR_LIST ((m->is_equiv ? REG_EQUIV
-                                                   : REG_EQUAL),
-                                                  m->set_src, REG_NOTES (i1));
+                           set_unique_reg_note (i1, m->is_equiv ? REG_EQUIV
+                                                    : REG_EQUAL, m->set_src);
                        }
+                     else if (m->insert_temp)
+                       {
+                         rtx *reg_map2 = (rtx *) xcalloc (REGNO (newreg), 
+                               sizeof(rtx));
+                         reg_map2 [m->regno] = newreg;
+
+                         i1 = loop_insn_hoist (loop, copy_rtx (PATTERN (p)));
+                         replace_regs (i1, reg_map2, REGNO (newreg), 1);
+                         free (reg_map2);
+                       }
                      else
-                       i1 = emit_insn_before (PATTERN (p), loop_start);
+                       i1 = loop_insn_hoist (loop, PATTERN (p));
 
                      if (REG_NOTES (i1) == 0)
                        {
                          REG_NOTES (i1) = REG_NOTES (p);
+                         REG_NOTES (p) = NULL;
 
                          /* If there is a REG_EQUAL note present whose value
                             is not loop invariant, then delete it, since it
@@ -2016,36 +2221,55 @@ move_movables (loop, movables, threshold, insn_count)
                         insn stream.  */
                      while (p && GET_CODE (p) == NOTE)
                        p = NEXT_INSN (temp) = NEXT_INSN (p);
+
+                     if (m->insert_temp)
+                       {
+                         rtx seq;
+                         /* Replace the original insn with a move from
+                            our newly created temp.  */
+                         start_sequence ();
+                         emit_move_insn (m->set_dest, newreg);
+                         seq = get_insns ();
+                         end_sequence ();
+                         emit_insn_before (seq, p);
+                       }
                    }
 
                  /* The more regs we move, the less we like moving them.  */
                  threshold -= 3;
                }
 
-             /* Any other movable that loads the same register
-                MUST be moved.  */
-             already_moved[regno] = 1;
-
-             /* This reg has been moved out of one loop.  */
-             regs->moved_once[regno] = 1;
+             m->done = 1;
 
-             /* The reg set here is now invariant.  */
-             if (! m->partial)
-               VARRAY_INT (regs->set_in_loop, regno) = 0;
+             if (!m->insert_temp)
+               {
+                 /* Any other movable that loads the same register
+                    MUST be moved.  */
+                 already_moved[regno] = 1;
 
-             m->done = 1;
+                 /* This reg has been moved out of one loop.  */
+                 regs->array[regno].moved_once = 1;
 
-             /* Change the length-of-life info for the register
-                to say it lives at least the full length of this loop.
-                This will help guide optimizations in outer loops.  */
+                 /* The reg set here is now invariant.  */
+                 if (! m->partial)
+                   {
+                     int i;
+                     for (i = 0; i < LOOP_REGNO_NREGS (regno, m->set_dest); i++)
+                       regs->array[regno+i].set_in_loop = 0;
+                   }
 
-             if (REGNO_FIRST_LUID (regno) > INSN_LUID (loop_start))
-               /* This is the old insn before all the moved insns.
-                  We can't use the moved insn because it is out of range
-                  in uid_luid.  Only the old insns have luids.  */
-               REGNO_FIRST_UID (regno) = INSN_UID (loop_start);
-             if (REGNO_LAST_LUID (regno) < INSN_LUID (loop_end))
-               REGNO_LAST_UID (regno) = INSN_UID (loop_end);
+                 /* Change the length-of-life info for the register
+                    to say it lives at least the full length of this loop.
+                    This will help guide optimizations in outer loops.  */
+
+                 if (REGNO_FIRST_LUID (regno) > INSN_LUID (loop_start))
+                   /* This is the old insn before all the moved insns.
+                      We can't use the moved insn because it is out of range
+                      in uid_luid.  Only the old insns have luids.  */
+                   REGNO_FIRST_UID (regno) = INSN_UID (loop_start);
+                 if (REGNO_LAST_LUID (regno) < INSN_LUID (loop_end))
+                   REGNO_LAST_UID (regno) = INSN_UID (loop_end);
+               }
 
              /* Combine with this moved insn any other matching movables.  */
 
@@ -2077,16 +2301,12 @@ move_movables (loop, movables, threshold, insn_count)
                         and prevent further processing of it.  */
                      m1->done = 1;
 
-                     /* if library call, delete all insn except last, which
-                        is deleted below */
+                     /* if library call, delete all insns.  */
                      if ((temp = find_reg_note (m1->insn, REG_RETVAL,
                                                 NULL_RTX)))
-                       {
-                         for (temp = XEXP (temp, 0); temp != m1->insn;
-                              temp = NEXT_INSN (temp))
-                           delete_insn (temp);
-                       }
-                     delete_insn (m1->insn);
+                       delete_insn_chain (XEXP (temp, 0), m1->insn);
+                     else
+                       delete_insn (m1->insn);
 
                      /* Any other movable that loads the same register
                         MUST be moved.  */
@@ -2095,7 +2315,13 @@ move_movables (loop, movables, threshold, insn_count)
                      /* The reg merged here is now invariant,
                         if the reg it matches is invariant.  */
                      if (! m->partial)
-                       VARRAY_INT (regs->set_in_loop, m1->regno) = 0;
+                       {
+                         int i;
+                         for (i = 0;
+                              i < LOOP_REGNO_NREGS (regno, m1->set_dest);
+                              i++)
+                           regs->array[m1->regno+i].set_in_loop = 0;
+                       }
                    }
            }
          else if (loop_dump_stream)
@@ -2153,7 +2379,7 @@ loop_movables_free (movables)
       m_next = m->next;
       free (m);
     }
-}  
+}
 \f
 #if 0
 /* Scan X and replace the address of any MEM in it with ADDR.
@@ -2163,9 +2389,9 @@ static void
 replace_call_address (x, reg, addr)
      rtx x, reg, addr;
 {
-  register enum rtx_code code;
-  register int i;
-  register const char *fmt;
+  enum rtx_code code;
+  int i;
+  const char *fmt;
 
   if (x == 0)
     return;
@@ -2211,7 +2437,7 @@ replace_call_address (x, reg, addr)
        replace_call_address (XEXP (x, i), reg, addr);
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            replace_call_address (XVECEXP (x, i, j), reg, addr);
        }
@@ -2227,9 +2453,9 @@ count_nonfixed_reads (loop, x)
      const struct loop *loop;
      rtx x;
 {
-  register enum rtx_code code;
-  register int i;
-  register const char *fmt;
+  enum rtx_code code;
+  int i;
+  const char *fmt;
   int value;
 
   if (x == 0)
@@ -2264,7 +2490,7 @@ count_nonfixed_reads (loop, x)
        value += count_nonfixed_reads (loop, XEXP (x, i));
       if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            value += count_nonfixed_reads (loop, XVECEXP (x, i, j));
        }
@@ -2273,7 +2499,7 @@ count_nonfixed_reads (loop, x)
 }
 \f
 /* Scan a loop setting the elements `cont', `vtop', `loops_enclosed',
-   `has_call', `has_volatile', `has_tablejump',
+   `has_call', `has_nonconst_call', `has_volatile', `has_tablejump',
    `unknown_address_altered', `unknown_constant_address_altered', and
    `num_mem_sets' in LOOP.  Also, fill in the array `mems' and the
    list `store_mems' in LOOP.  */
@@ -2282,7 +2508,7 @@ static void
 prescan_loop (loop)
      struct loop *loop;
 {
-  register int level = 1;
+  int level = 1;
   rtx insn;
   struct loop_info *loop_info = LOOP_INFO (loop);
   rtx start = loop->start;
@@ -2294,7 +2520,10 @@ prescan_loop (loop)
   rtx exit_target = next_nonnote_insn (end);
 
   loop_info->has_indirect_jump = indirect_jump_in_function;
+  loop_info->pre_header_has_call = 0;
   loop_info->has_call = 0;
+  loop_info->has_nonconst_call = 0;
+  loop_info->has_prefetch = 0;
   loop_info->has_volatile = 0;
   loop_info->has_tablejump = 0;
   loop_info->has_multiple_exit_targets = 0;
@@ -2306,12 +2535,25 @@ prescan_loop (loop)
   loop_info->first_loop_store_insn = NULL_RTX;
   loop_info->mems_idx = 0;
   loop_info->num_mem_sets = 0;
+  /* If loop opts run twice, this was set on 1st pass for 2nd.  */
+  loop_info->preconditioned = NOTE_PRECONDITIONED (end);
+
+  for (insn = start; insn && GET_CODE (insn) != CODE_LABEL;
+       insn = PREV_INSN (insn))
+    {
+      if (GET_CODE (insn) == CALL_INSN)
+       {
+         loop_info->pre_header_has_call = 1;
+         break;
+       }
+    }
 
   for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
        insn = NEXT_INSN (insn))
     {
-      if (GET_CODE (insn) == NOTE)
+      switch (GET_CODE (insn))
        {
+       case NOTE:
          if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
            {
              ++level;
@@ -2319,21 +2561,100 @@ prescan_loop (loop)
              loop->level++;
            }
          else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+           --level;
+         break;
+
+       case CALL_INSN:
+         if (! CONST_OR_PURE_CALL_P (insn))
            {
-             --level;
+             loop_info->unknown_address_altered = 1;
+             loop_info->has_nonconst_call = 1;
            }
-       }
-      else if (GET_CODE (insn) == CALL_INSN)
-       {
-         if (! CONST_CALL_P (insn))
-           loop_info->unknown_address_altered = 1;
+         else if (pure_call_p (insn))
+           loop_info->has_nonconst_call = 1;
          loop_info->has_call = 1;
-       }
-      else if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
-       {
-         rtx label1 = NULL_RTX;
-         rtx label2 = NULL_RTX;
+         if (can_throw_internal (insn))
+           loop_info->has_multiple_exit_targets = 1;
+
+         /* Calls initializing constant objects have CLOBBER of MEM /u in the
+            attached FUNCTION_USAGE expression list, not accounted for by the
+            code above. We should note these to avoid missing dependencies in
+            later references.  */
+         {
+           rtx fusage_entry;
+           
+           for (fusage_entry = CALL_INSN_FUNCTION_USAGE (insn); 
+                fusage_entry; fusage_entry = XEXP (fusage_entry, 1))
+             {
+               rtx fusage = XEXP (fusage_entry, 0);
+
+               if (GET_CODE (fusage) == CLOBBER
+                   && GET_CODE (XEXP (fusage, 0)) == MEM
+                   && RTX_UNCHANGING_P (XEXP (fusage, 0)))
+                 {
+                   note_stores (fusage, note_addr_stored, loop_info);
+                   if (! loop_info->first_loop_store_insn
+                       && loop_info->store_mems)
+                     loop_info->first_loop_store_insn = insn;
+                 }
+             }
+         }
+         break;
+
+       case JUMP_INSN:
+         if (! loop_info->has_multiple_exit_targets)
+           {
+             rtx set = pc_set (insn);
+
+             if (set)
+               {
+                 rtx src = SET_SRC (set);
+                 rtx label1, label2;
+
+                 if (GET_CODE (src) == IF_THEN_ELSE)
+                   {
+                     label1 = XEXP (src, 1);
+                     label2 = XEXP (src, 2);
+                   }
+                 else
+                   {
+                     label1 = src;
+                     label2 = NULL_RTX;
+                   }
 
+                 do
+                   {
+                     if (label1 && label1 != pc_rtx)
+                       {
+                         if (GET_CODE (label1) != LABEL_REF)
+                           {
+                             /* Something tricky.  */
+                             loop_info->has_multiple_exit_targets = 1;
+                             break;
+                           }
+                         else if (XEXP (label1, 0) != exit_target
+                                  && LABEL_OUTSIDE_LOOP_P (label1))
+                           {
+                             /* A jump outside the current loop.  */
+                             loop_info->has_multiple_exit_targets = 1;
+                             break;
+                           }
+                       }
+
+                     label1 = label2;
+                     label2 = NULL_RTX;
+                   }
+                 while (label1);
+               }
+             else
+               {
+                 /* A return, or something tricky.  */
+                 loop_info->has_multiple_exit_targets = 1;
+               }
+           }
+         /* FALLTHRU */
+
+       case INSN:
          if (volatile_refs_p (PATTERN (insn)))
            loop_info->has_volatile = 1;
 
@@ -2346,54 +2667,19 @@ prescan_loop (loop)
          if (! loop_info->first_loop_store_insn && loop_info->store_mems)
            loop_info->first_loop_store_insn = insn;
 
-         if (! loop_info->has_multiple_exit_targets
-             && GET_CODE (insn) == JUMP_INSN
-             && GET_CODE (PATTERN (insn)) == SET
-             && SET_DEST (PATTERN (insn)) == pc_rtx)
-           {
-             if (GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
-               {
-                 label1 = XEXP (SET_SRC (PATTERN (insn)), 1);
-                 label2 = XEXP (SET_SRC (PATTERN (insn)), 2);
-               }
-             else
-               {
-                 label1 = SET_SRC (PATTERN (insn));
-               }
+         if (flag_non_call_exceptions && can_throw_internal (insn))
+           loop_info->has_multiple_exit_targets = 1;
+         break;
 
-             do
-               {
-                 if (label1 && label1 != pc_rtx)
-                   {
-                     if (GET_CODE (label1) != LABEL_REF)
-                       {
-                         /* Something tricky.  */
-                         loop_info->has_multiple_exit_targets = 1;
-                         break;
-                       }
-                     else if (XEXP (label1, 0) != exit_target
-                              && LABEL_OUTSIDE_LOOP_P (label1))
-                       {
-                         /* A jump outside the current loop.  */
-                         loop_info->has_multiple_exit_targets = 1;
-                         break;
-                       }
-                   }
-
-                 label1 = label2;
-                 label2 = NULL_RTX;
-               }
-             while (label1);
-           }
+       default:
+         break;
        }
-      else if (GET_CODE (insn) == RETURN)
-       loop_info->has_multiple_exit_targets = 1;
     }
 
   /* Now, rescan the loop, setting up the LOOP_MEMS array.  */
   if (/* An exception thrown by a called function might land us
         anywhere.  */
-      ! loop_info->has_call
+      ! loop_info->has_nonconst_call
       /* We don't want loads for MEMs moved to a location before the
         one at which their stack memory becomes allocated.  (Note
         that this is not a problem for malloc, etc., since those
@@ -2426,6 +2712,17 @@ prescan_loop (loop)
     }
 }
 \f
+/* Invalidate all loops containing LABEL.  */
+
+static void
+invalidate_loops_containing_label (label)
+     rtx label;
+{
+  struct loop *loop;
+  for (loop = uid_loop[INSN_UID (label)]; loop; loop = loop->outer)
+    loop->invalid = 1;
+}
+
 /* Scan the function looking for loops.  Record the start and end of each loop.
    Also mark as invalid loops any loops that contain a setjmp or are branched
    to from outside the loop.  */
@@ -2470,19 +2767,6 @@ find_and_verify_loops (f, loops)
            current_loop = next_loop;
            break;
 
-         case NOTE_INSN_SETJMP:
-           /* In this case, we must invalidate our current loop and any
-              enclosing loop.  */
-           for (loop = current_loop; loop; loop = loop->outer)
-             {
-               loop->invalid = 1;
-               if (loop_dump_stream)
-                 fprintf (loop_dump_stream,
-                          "\nLoop at %d ignored due to setjmp.\n",
-                          INSN_UID (loop->start));
-             }
-           break;
-
          case NOTE_INSN_LOOP_CONT:
            current_loop->cont = insn;
            break;
@@ -2503,6 +2787,21 @@ find_and_verify_loops (f, loops)
            break;
          }
 
+      if (GET_CODE (insn) == CALL_INSN
+         && find_reg_note (insn, REG_SETJMP, NULL))
+       {
+         /* In this case, we must invalidate our current loop and any
+            enclosing loop.  */
+         for (loop = current_loop; loop; loop = loop->outer)
+           {
+             loop->invalid = 1;
+             if (loop_dump_stream)
+               fprintf (loop_dump_stream,
+                        "\nLoop at %d ignored due to setjmp.\n",
+                        INSN_UID (loop->start));
+           }
+       }
+
       /* Note that this will mark the NOTE_INSN_LOOP_END note as being in the
         enclosing loop, but this doesn't matter.  */
       uid_loop[INSN_UID (insn)] = current_loop;
@@ -2510,23 +2809,12 @@ find_and_verify_loops (f, loops)
 
   /* Any loop containing a label used in an initializer must be invalidated,
      because it can be jumped into from anywhere.  */
-
   for (label = forced_labels; label; label = XEXP (label, 1))
-    {
-      for (loop = uid_loop[INSN_UID (XEXP (label, 0))];
-          loop; loop = loop->outer)
-       loop->invalid = 1;
-    }
+    invalidate_loops_containing_label (XEXP (label, 0));
 
   /* Any loop containing a label used for an exception handler must be
      invalidated, because it can be jumped into from anywhere.  */
-
-  for (label = exception_handler_labels; label; label = XEXP (label, 1))
-    {
-      for (loop = uid_loop[INSN_UID (XEXP (label, 0))];
-          loop; loop = loop->outer)
-       loop->invalid = 1;
-    }
+  for_each_eh_label (invalidate_loops_containing_label);
 
   /* Now scan all insn's in the function.  If any JUMP_INSN branches into a
      loop that it is not contained within, that loop is marked invalid.
@@ -2550,11 +2838,7 @@ find_and_verify_loops (f, loops)
          {
            rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
            if (note)
-             {
-               for (loop = uid_loop[INSN_UID (XEXP (note, 0))];
-                    loop; loop = loop->outer)
-                 loop->invalid = 1;
-             }
+             invalidate_loops_containing_label (XEXP (note, 0));
          }
 
        if (GET_CODE (insn) != JUMP_INSN)
@@ -2634,6 +2918,14 @@ find_and_verify_loops (f, loops)
                  = JUMP_LABEL (insn) ? JUMP_LABEL (insn) : get_last_insn ();
                struct loop *target_loop = uid_loop[INSN_UID (target)];
                rtx loc, loc2;
+               rtx tmp;
+
+               /* Search for possible garbage past the conditional jumps
+                  and look for the last barrier.  */
+               for (tmp = last_insn_to_move;
+                    tmp && GET_CODE (tmp) != CODE_LABEL; tmp = NEXT_INSN (tmp))
+                 if (GET_CODE (tmp) == BARRIER)
+                   last_insn_to_move = tmp;
 
                for (loc = target; loc; loc = PREV_INSN (loc))
                  if (GET_CODE (loc) == BARRIER
@@ -2676,8 +2968,8 @@ find_and_verify_loops (f, loops)
 
                        /* If no suitable BARRIER was found, create a suitable
                           one before TARGET.  Since TARGET is a fall through
-                          path, we'll need to insert an jump around our block
-                          and a add a BARRIER before TARGET.
+                          path, we'll need to insert a jump around our block
+                          and add a BARRIER before TARGET.
 
                           This creates an extra unconditional jump outside
                           the loop.  However, the benefits of removing rarely
@@ -2697,8 +2989,8 @@ find_and_verify_loops (f, loops)
 
                        /* Include the BARRIER after INSN and copy the
                           block after LOC.  */
-                       new_label = squeeze_notes (new_label,
-                                                  last_insn_to_move);
+                       if (squeeze_notes (&new_label, &last_insn_to_move))
+                         abort ();
                        reorder_insns (new_label, last_insn_to_move, loc);
 
                        /* All those insns are now in TARGET_LOOP.  */
@@ -2748,7 +3040,7 @@ find_and_verify_loops (f, loops)
                        if (JUMP_LABEL (insn) != 0
                            && (next_real_insn (JUMP_LABEL (insn))
                                == next_real_insn (insn)))
-                         delete_insn (insn);
+                         delete_related_insns (insn);
                      }
 
                    /* Continue the loop after where the conditional
@@ -2758,7 +3050,7 @@ find_and_verify_loops (f, loops)
                    insn = NEXT_INSN (cond_label);
 
                    if (--LABEL_NUSES (cond_label) == 0)
-                     delete_insn (cond_label);
+                     delete_related_insns (cond_label);
 
                    /* This loop will be continued with NEXT_INSN (insn).  */
                    insn = PREV_INSN (insn);
@@ -2996,8 +3288,8 @@ note_set_pseudo_multiple_uses (x, y, data)
   /* If we do not have usage information, or if we know the register
      is used more than once, note that fact for check_dbra_loop.  */
   if (REGNO (x) >= max_reg_before_loop
-      || ! VARRAY_RTX (regs->single_usage, REGNO (x))
-      || VARRAY_RTX (regs->single_usage, REGNO (x)) == const0_rtx)
+      || ! regs->array[REGNO (x)].single_usage
+      || regs->array[REGNO (x)].single_usage == const0_rtx)
     regs->multiple_uses = 1;
 }
 \f
@@ -3011,13 +3303,13 @@ note_set_pseudo_multiple_uses (x, y, data)
 int
 loop_invariant_p (loop, x)
      const struct loop *loop;
-     register rtx x;
+     rtx x;
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
-  register int i;
-  register enum rtx_code code;
-  register const char *fmt;
+  int i;
+  enum rtx_code code;
+  const char *fmt;
   int conditional = 0;
   rtx mem_list_entry;
 
@@ -3042,7 +3334,7 @@ loop_invariant_p (loop, x)
 
         We don't know the loop bounds here though, so just fail for all
         labels.  */
-      if (flag_unroll_loops)
+      if (flag_old_unroll_loops)
        return 0;
       else
        return 1;
@@ -3057,7 +3349,7 @@ loop_invariant_p (loop, x)
         since the reg might be set by initialization within the loop.  */
 
       if ((x == frame_pointer_rtx || x == hard_frame_pointer_rtx
-          || x == arg_pointer_rtx)
+          || x == arg_pointer_rtx || x == pic_offset_table_rtx)
          && ! current_function_has_nonlocal_goto)
        return 1;
 
@@ -3065,10 +3357,17 @@ loop_invariant_p (loop, x)
          && REGNO (x) < FIRST_PSEUDO_REGISTER && call_used_regs[REGNO (x)])
        return 0;
 
-      if (VARRAY_INT (regs->set_in_loop, REGNO (x)) < 0)
+      /* Out-of-range regs can occur when we are called from unrolling.
+        These have always been created by the unroller and are set in
+        the loop, hence are never invariant.  */
+
+      if (REGNO (x) >= (unsigned) regs->num)
+       return 0;
+
+      if (regs->array[REGNO (x)].set_in_loop < 0)
        return 2;
 
-      return VARRAY_INT (regs->set_in_loop, REGNO (x)) == 0;
+      return regs->array[REGNO (x)].set_in_loop == 0;
 
     case MEM:
       /* Volatile memory references must be rejected.  Do this before
@@ -3115,7 +3414,7 @@ loop_invariant_p (loop, x)
        }
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            {
              int tem = loop_invariant_p (loop, XVECEXP (x, i, j));
@@ -3153,7 +3452,7 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
   rtx temp;
   /* Number of sets we have to insist on finding after INSN.  */
   int count = n_sets - 1;
-  int old = VARRAY_INT (regs->set_in_loop, regno);
+  int old = regs->array[regno].set_in_loop;
   int value = 0;
   int this;
 
@@ -3161,11 +3460,11 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
   if (n_sets == 127)
     return 0;
 
-  VARRAY_INT (regs->set_in_loop, regno) = 0;
+  regs->array[regno].set_in_loop = 0;
 
   while (count > 0)
     {
-      register enum rtx_code code;
+      enum rtx_code code;
       rtx set;
 
       p = NEXT_INSN (p);
@@ -3200,12 +3499,12 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
        count--;
       else if (code != NOTE)
        {
-         VARRAY_INT (regs->set_in_loop, regno) = old;
+         regs->array[regno].set_in_loop = old;
          return 0;
        }
     }
 
-  VARRAY_INT (regs->set_in_loop, regno) = old;
+  regs->array[regno].set_in_loop = old;
   /* If loop_invariant_p ever returned 2, we return 2.  */
   return 1 + (value & 2);
 }
@@ -3222,12 +3521,12 @@ all_sets_invariant_p (reg, insn, table)
      rtx reg, insn;
      short *table;
 {
-  register rtx p = insn;
-  register int regno = REGNO (reg);
+  rtx p = insn;
+  int regno = REGNO (reg);
 
   while (1)
     {
-      register enum rtx_code code;
+      enum rtx_code code;
       p = NEXT_INSN (p);
       code = GET_CODE (p);
       if (code == CODE_LABEL || code == JUMP_INSN)
@@ -3248,19 +3547,19 @@ all_sets_invariant_p (reg, insn, table)
    a different insn, set USAGE[REGNO] to const0_rtx.  */
 
 static void
-find_single_use_in_loop (insn, x, usage)
+find_single_use_in_loop (regs, insn, x)
+     struct loop_regs *regs;
      rtx insn;
      rtx x;
-     varray_type usage;
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt = GET_RTX_FORMAT (code);
   int i, j;
 
   if (code == REG)
-    VARRAY_RTX (usage, REGNO (x))
-      = (VARRAY_RTX (usage, REGNO (x)) != 0
-        && VARRAY_RTX (usage, REGNO (x)) != insn)
+    regs->array[REGNO (x)].single_usage
+      = (regs->array[REGNO (x)].single_usage != 0
+        && regs->array[REGNO (x)].single_usage != insn)
        ? const0_rtx : insn;
 
   else if (code == SET)
@@ -3270,34 +3569,34 @@ find_single_use_in_loop (insn, x, usage)
         show up as a potential movable so we don't care how USAGE is set
         for it.  */
       if (GET_CODE (SET_DEST (x)) != REG)
-       find_single_use_in_loop (insn, SET_DEST (x), usage);
-      find_single_use_in_loop (insn, SET_SRC (x), usage);
+       find_single_use_in_loop (regs, insn, SET_DEST (x));
+      find_single_use_in_loop (regs, insn, SET_SRC (x));
     }
   else
     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
       {
        if (fmt[i] == 'e' && XEXP (x, i) != 0)
-         find_single_use_in_loop (insn, XEXP (x, i), usage);
+         find_single_use_in_loop (regs, insn, XEXP (x, i));
        else if (fmt[i] == 'E')
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           find_single_use_in_loop (insn, XVECEXP (x, i, j), usage);
+           find_single_use_in_loop (regs, insn, XVECEXP (x, i, j));
       }
 }
 \f
 /* Count and record any set in X which is contained in INSN.  Update
-   MAY_NOT_MOVE and LAST_SET for any register set in X.  */
+   REGS->array[I].MAY_NOT_OPTIMIZE and LAST_SET for any register I set
+   in X.  */
 
 static void
-count_one_set (regs, insn, x, may_not_move, last_set)
+count_one_set (regs, insn, x, last_set)
      struct loop_regs *regs;
      rtx insn, x;
-     varray_type may_not_move;
      rtx *last_set;
 {
   if (GET_CODE (x) == CLOBBER && GET_CODE (XEXP (x, 0)) == REG)
     /* Don't move a reg that has an explicit clobber.
        It's not worth the pain to try to do it correctly.  */
-    VARRAY_CHAR (may_not_move, REGNO (XEXP (x, 0))) = 1;
+    regs->array[REGNO (XEXP (x, 0))].may_not_optimize = 1;
 
   if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
     {
@@ -3309,89 +3608,29 @@ count_one_set (regs, insn, x, may_not_move, last_set)
        dest = XEXP (dest, 0);
       if (GET_CODE (dest) == REG)
        {
-         register int regno = REGNO (dest);
-         /* If this is the first setting of this reg
-            in current basic block, and it was set before,
-            it must be set in two basic blocks, so it cannot
-            be moved out of the loop.  */
-         if (VARRAY_INT (regs->set_in_loop, regno) > 0
-             && last_set[regno] == 0)
-           VARRAY_CHAR (may_not_move, regno) = 1;
-         /* If this is not first setting in current basic block,
-            see if reg was used in between previous one and this.
-            If so, neither one can be moved.  */
-         if (last_set[regno] != 0
-             && reg_used_between_p (dest, last_set[regno], insn))
-           VARRAY_CHAR (may_not_move, regno) = 1;
-         if (VARRAY_INT (regs->set_in_loop, regno) < 127)
-           ++VARRAY_INT (regs->set_in_loop, regno);
-         last_set[regno] = insn;
-       }
-    }
-}
-
-/* Increment REGS->SET_IN_LOOP at the index of each register
-   that is modified by an insn between FROM and TO.
-   If the value of an element of REGS->SET_IN_LOOP becomes 127 or more,
-   stop incrementing it, to avoid overflow.
-
-   Store in SINGLE_USAGE[I] the single insn in which register I is
-   used, if it is only used once.  Otherwise, it is set to 0 (for no
-   uses) or const0_rtx for more than one use.  This parameter may be zero,
-   in which case this processing is not done.
-
-   Store in *COUNT_PTR the number of actual instruction
-   in the loop.  We use this to decide what is worth moving out.  */
-
-/* last_set[n] is nonzero iff reg n has been set in the current basic block.
-   In that case, it is the insn that last set reg n.  */
-
-static void
-count_loop_regs_set (loop, may_not_move, single_usage, count_ptr, nregs)
-     const struct loop *loop;
-     varray_type may_not_move;
-     varray_type single_usage;
-     int *count_ptr;
-     int nregs;
-{
-  struct loop_regs *regs = LOOP_REGS (loop);
-  register rtx *last_set = (rtx *) xcalloc (nregs, sizeof (rtx));
-  register rtx insn;
-  register int count = 0;
-
-  for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
-       insn = NEXT_INSN (insn))
-    {
-      if (INSN_P (insn))
-       {
-         ++count;
-
-         /* Record registers that have exactly one use.  */
-         find_single_use_in_loop (insn, PATTERN (insn), single_usage);
-
-         /* Include uses in REG_EQUAL notes.  */
-         if (REG_NOTES (insn))
-           find_single_use_in_loop (insn, REG_NOTES (insn), single_usage);
-
-         if (GET_CODE (PATTERN (insn)) == SET
-             || GET_CODE (PATTERN (insn)) == CLOBBER)
-           count_one_set (regs, insn, PATTERN (insn), may_not_move, last_set);
-         else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+         int i;
+         int regno = REGNO (dest);
+         for (i = 0; i < LOOP_REGNO_NREGS (regno, dest); i++)
            {
-             register int i;
-             for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
-               count_one_set (regs, insn, XVECEXP (PATTERN (insn), 0, i),
-                              may_not_move, last_set);
+             /* If this is the first setting of this reg
+                in current basic block, and it was set before,
+                it must be set in two basic blocks, so it cannot
+                be moved out of the loop.  */
+             if (regs->array[regno].set_in_loop > 0
+                 && last_set == 0)
+               regs->array[regno+i].may_not_optimize = 1;
+             /* If this is not first setting in current basic block,
+                see if reg was used in between previous one and this.
+                If so, neither one can be moved.  */
+             if (last_set[regno] != 0
+                 && reg_used_between_p (dest, last_set[regno], insn))
+               regs->array[regno+i].may_not_optimize = 1;
+             if (regs->array[regno+i].set_in_loop < 127)
+               ++regs->array[regno+i].set_in_loop;
+             last_set[regno+i] = insn;
            }
        }
-
-      if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
-       memset ((char *) last_set, 0, nregs * sizeof (rtx));
     }
-  *count_ptr = count;
-
-  /* Clean up.  */
-  free (last_set);
 }
 \f
 /* Given a loop that is bounded by LOOP->START and LOOP->END and that
@@ -3425,106 +3664,747 @@ loop_reg_used_before_p (loop, set, insn)
   return 0;
 }
 \f
-/* A "basic induction variable" or biv is a pseudo reg that is set
-   (within this loop) only by incrementing or decrementing it.  */
-/* A "general induction variable" or giv is a pseudo reg whose
-   value is a linear function of a biv.  */
 
-/* Bivs are recognized by `basic_induction_var';
-   Givs by `general_induction_var'.  */
+/* Information we collect about arrays that we might want to prefetch.  */
+struct prefetch_info
+{
+  struct iv_class *class;      /* Class this prefetch is based on.  */
+  struct induction *giv;       /* GIV this prefetch is based on.  */
+  rtx base_address;            /* Start prefetching from this address plus
+                                  index.  */
+  HOST_WIDE_INT index;
+  HOST_WIDE_INT stride;                /* Prefetch stride in bytes in each
+                                  iteration.  */
+  unsigned int bytes_accessed; /* Sum of sizes of all accesses to this
+                                  prefetch area in one iteration.  */
+  unsigned int total_bytes;    /* Total bytes loop will access in this block.
+                                  This is set only for loops with known
+                                  iteration counts and is 0xffffffff
+                                  otherwise.  */
+  int prefetch_in_loop;                /* Number of prefetch insns in loop.  */
+  int prefetch_before_loop;    /* Number of prefetch insns before loop.  */
+  unsigned int write : 1;      /* 1 for read/write prefetches.  */
+};
 
-/* Communication with routines called via `note_stores'.  */
+/* Data used by check_store function.  */
+struct check_store_data
+{
+  rtx mem_address;
+  int mem_write;
+};
 
-static rtx note_insn;
+static void check_store PARAMS ((rtx, rtx, void *));
+static void emit_prefetch_instructions PARAMS ((struct loop *));
+static int rtx_equal_for_prefetch_p PARAMS ((rtx, rtx));
 
-/* Dummy register to have non-zero DEST_REG for DEST_ADDR type givs.  */
+/* Set mem_write when mem_address is found.  Used as callback to
+   note_stores.  */
+static void
+check_store (x, pat, data)
+     rtx x, pat ATTRIBUTE_UNUSED;
+     void *data;
+{
+  struct check_store_data *d = (struct check_store_data *) data;
 
-static rtx addr_placeholder;
+  if ((GET_CODE (x) == MEM) && rtx_equal_p (d->mem_address, XEXP (x, 0)))
+    d->mem_write = 1;
+}
+\f
+/* Like rtx_equal_p, but attempts to swap commutative operands.  This is
+   important to get some addresses combined.  Later more sophisticated
+   transformations can be added when necessary.
 
-/* ??? Unfinished optimizations, and possible future optimizations,
-   for the strength reduction code.  */
+   ??? Same trick with swapping operand is done at several other places.
+   It can be nice to develop some common way to handle this.  */
 
-/* ??? The interaction of biv elimination, and recognition of 'constant'
-   bivs, may cause problems.  */
+static int
+rtx_equal_for_prefetch_p (x, y)
+     rtx x, y;
+{
+  int i;
+  int j;
+  enum rtx_code code = GET_CODE (x);
+  const char *fmt;
 
-/* ??? Add heuristics so that DEST_ADDR strength reduction does not cause
-   performance problems.
+  if (x == y)
+    return 1;
+  if (code != GET_CODE (y))
+    return 0;
 
-   Perhaps don't eliminate things that can be combined with an addressing
-   mode.  Find all givs that have the same biv, mult_val, and add_val;
-   then for each giv, check to see if its only use dies in a following
-   memory address.  If so, generate a new memory address and check to see
-   if it is valid.   If it is valid, then store the modified memory address,
-   otherwise, mark the giv as not done so that it will get its own iv.  */
+  code = GET_CODE (x);
 
-/* ??? Could try to optimize branches when it is known that a biv is always
-   positive.  */
+  if (GET_RTX_CLASS (code) == 'c')
+    {
+      return ((rtx_equal_for_prefetch_p (XEXP (x, 0), XEXP (y, 0))
+              && rtx_equal_for_prefetch_p (XEXP (x, 1), XEXP (y, 1)))
+             || (rtx_equal_for_prefetch_p (XEXP (x, 0), XEXP (y, 1))
+                 && rtx_equal_for_prefetch_p (XEXP (x, 1), XEXP (y, 0))));
+    }
+  /* Compare the elements.  If any pair of corresponding elements fails to
+     match, return 0 for the whole thing.  */
 
-/* ??? When replace a biv in a compare insn, we should replace with closest
-   giv so that an optimized branch can still be recognized by the combiner,
-   e.g. the VAX acb insn.  */
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      switch (fmt[i])
+       {
+       case 'w':
+         if (XWINT (x, i) != XWINT (y, i))
+           return 0;
+         break;
 
-/* ??? Many of the checks involving uid_luid could be simplified if regscan
-   was rerun in loop_optimize whenever a register was added or moved.
-   Also, some of the optimizations could be a little less conservative.  */
+       case 'i':
+         if (XINT (x, i) != XINT (y, i))
+           return 0;
+         break;
+
+       case 'E':
+         /* Two vectors must have the same length.  */
+         if (XVECLEN (x, i) != XVECLEN (y, i))
+           return 0;
+
+         /* And the corresponding elements must match.  */
+         for (j = 0; j < XVECLEN (x, i); j++)
+           if (rtx_equal_for_prefetch_p (XVECEXP (x, i, j),
+                                         XVECEXP (y, i, j)) == 0)
+             return 0;
+         break;
+
+       case 'e':
+         if (rtx_equal_for_prefetch_p (XEXP (x, i), XEXP (y, i)) == 0)
+           return 0;
+         break;
+
+       case 's':
+         if (strcmp (XSTR (x, i), XSTR (y, i)))
+           return 0;
+         break;
+
+       case 'u':
+         /* These are just backpointers, so they don't matter.  */
+         break;
+
+       case '0':
+         break;
+
+         /* It is believed that rtx's at this level will never
+            contain anything but integers and other rtx's,
+            except for within LABEL_REFs and SYMBOL_REFs.  */
+       default:
+         abort ();
+       }
+    }
+  return 1;
+}
 \f
-/* Scan the loop body and call FNCALL for each insn.  In the addition to the
-   LOOP and INSN parameters pass MAYBE_MULTIPLE and NOT_EVERY_ITERATION to the
-   callback.
+/* Remove constant addition value from the expression X (when present)
+   and return it.  */
 
-   NOT_EVERY_ITERATION if current insn is not executed at least once for every
-   loop iteration except for the last one.
+static HOST_WIDE_INT
+remove_constant_addition (x)
+     rtx *x;
+{
+  HOST_WIDE_INT addval = 0;
+  rtx exp = *x;
 
-   MAYBE_MULTIPLE is 1 if current insn may be executed more than once for every
-   loop iteration.
- */
-void
-for_each_insn_in_loop (loop, fncall)
+  /* Avoid clobbering a shared CONST expression.  */
+  if (GET_CODE (exp) == CONST)
+    {
+      if (GET_CODE (XEXP (exp, 0)) == PLUS
+         && GET_CODE (XEXP (XEXP (exp, 0), 0)) == SYMBOL_REF
+         && GET_CODE (XEXP (XEXP (exp, 0), 1)) == CONST_INT)
+       {
+         *x = XEXP (XEXP (exp, 0), 0);
+         return INTVAL (XEXP (XEXP (exp, 0), 1));
+       }
+      return 0;
+    }
+
+  if (GET_CODE (exp) == CONST_INT)
+    {
+      addval = INTVAL (exp);
+      *x = const0_rtx;
+    }
+
+  /* For plus expression recurse on ourself.  */
+  else if (GET_CODE (exp) == PLUS)
+    {
+      addval += remove_constant_addition (&XEXP (exp, 0));
+      addval += remove_constant_addition (&XEXP (exp, 1));
+
+      /* In case our parameter was constant, remove extra zero from the
+        expression.  */
+      if (XEXP (exp, 0) == const0_rtx)
+       *x = XEXP (exp, 1);
+      else if (XEXP (exp, 1) == const0_rtx)
+       *x = XEXP (exp, 0);
+    }
+
+  return addval;
+}
+
+/* Attempt to identify accesses to arrays that are most likely to cause cache
+   misses, and emit prefetch instructions a few prefetch blocks forward.
+
+   To detect the arrays we use the GIV information that was collected by the
+   strength reduction pass.
+
+   The prefetch instructions are generated after the GIV information is done
+   and before the strength reduction process. The new GIVs are injected into
+   the strength reduction tables, so the prefetch addresses are optimized as
+   well.
+
+   GIVs are split into base address, stride, and constant addition values.
+   GIVs with the same address, stride and close addition values are combined
+   into a single prefetch.  Also writes to GIVs are detected, so that prefetch
+   for write instructions can be used for the block we write to, on machines
+   that support write prefetches.
+
+   Several heuristics are used to determine when to prefetch.  They are
+   controlled by defined symbols that can be overridden for each target.  */
+
+static void
+emit_prefetch_instructions (loop)
      struct loop *loop;
-     loop_insn_callback fncall;
 {
-  /* This is 1 if current insn is not executed at least once for every loop
-     iteration.  */
-  int not_every_iteration = 0;
-  int maybe_multiple = 0;
-  int past_loop_latch = 0;
-  int loop_depth = 0;
-  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 (prev_nonnote_insn (loop->scan_start) != prev_nonnote_insn (loop->start))
-    maybe_multiple = back_branch_in_range_p (loop, loop->scan_start);
+  int num_prefetches = 0;
+  int num_real_prefetches = 0;
+  int num_real_write_prefetches = 0;
+  int num_prefetches_before = 0;
+  int num_write_prefetches_before = 0;
+  int ahead = 0;
+  int i;
+  struct iv_class *bl;
+  struct induction *iv;
+  struct prefetch_info info[MAX_PREFETCHES];
+  struct loop_ivs *ivs = LOOP_IVS (loop);
 
-  /* Scan through loop to find all possible bivs.  */
+  if (!HAVE_prefetch)
+    return;
 
-  for (p = next_insn_in_loop (loop, loop->scan_start);
-       p != NULL_RTX;
-       p = next_insn_in_loop (loop, p))
+  /* 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)
     {
-      p = fncall (loop, p, not_every_iteration, maybe_multiple);
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream, "Prefetch: ignoring loop: has call.\n");
 
-      /* Past CODE_LABEL, we get to insns that may be executed multiple
-         times.  The only way we can be sure that they can't is if every
-         jump insn between here and the end of the loop either
-         returns, exits the loop, is a jump to a location that is still
-         behind the label, or is a jump to the loop start.  */
+      return;
+    }
 
-      if (GET_CODE (p) == CODE_LABEL)
-       {
-         rtx insn = p;
+  /* Don't prefetch in loops known to have few iterations.  */
+  if (PREFETCH_NO_LOW_LOOPCNT
+      && LOOP_INFO (loop)->n_iterations
+      && LOOP_INFO (loop)->n_iterations <= PREFETCH_LOW_LOOPCNT)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Prefetch: ignoring loop: not enough iterations.\n");
+      return;
+    }
 
-         maybe_multiple = 0;
+  /* Search all induction variables and pick those interesting for the prefetch
+     machinery.  */
+  for (bl = ivs->list; bl; bl = bl->next)
+    {
+      struct induction *biv = bl->biv, *biv1;
+      int basestride = 0;
 
-         while (1)
+      biv1 = biv;
+
+      /* Expect all BIVs to be executed in each iteration.  This makes our
+        analysis more conservative.  */
+      while (biv1)
+       {
+         /* Discard non-constant additions that we can't handle well yet, and
+            BIVs that are executed multiple times; such BIVs ought to be
+            handled in the nested loop.  We accept not_every_iteration BIVs,
+            since these only result in larger strides and make our
+            heuristics more conservative.  */
+         if (GET_CODE (biv->add_val) != CONST_INT)
            {
-             insn = NEXT_INSN (insn);
-             if (insn == loop->scan_start)
-               break;
-             if (insn == loop->end)
+             if (loop_dump_stream)
                {
-                 if (loop->top != 0)
-                   insn = loop->top;
+                 fprintf (loop_dump_stream,
+                   "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");
+               }
+             break;
+           }
+
+         if (biv->maybe_multiple)
+           {
+             if (loop_dump_stream)
+               {
+                 fprintf (loop_dump_stream,
+                          "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");
+               }
+             break;
+           }
+
+         basestride += INTVAL (biv1->add_val);
+         biv1 = biv1->next_iv;
+       }
+
+      if (biv1 || !basestride)
+       continue;
+
+      for (iv = bl->giv; iv; iv = iv->next_iv)
+       {
+         rtx address;
+         rtx temp;
+         HOST_WIDE_INT index = 0;
+         int add = 1;
+         HOST_WIDE_INT stride = 0;
+         int stride_sign = 1;
+         struct check_store_data d;
+         const char *ignore_reason = NULL;
+         int size = GET_MODE_SIZE (GET_MODE (iv));
+
+         /* See whether an induction variable is interesting to us and if
+            not, report the reason.  */
+         if (iv->giv_type != DEST_ADDR)
+           ignore_reason = "giv is not a destination address";
+
+         /* We are interested only in constant stride memory references
+            in order to be able to compute density easily.  */
+         else if (GET_CODE (iv->mult_val) != CONST_INT)
+           ignore_reason = "stride is not constant";
+
+         else
+           {
+             stride = INTVAL (iv->mult_val) * basestride;
+             if (stride < 0)
+               {
+                 stride = -stride;
+                 stride_sign = -1;
+               }
+
+             /* On some targets, reversed order prefetches are not
+                worthwhile.  */
+             if (PREFETCH_NO_REVERSE_ORDER && stride_sign < 0)
+               ignore_reason = "reversed order stride";
+
+             /* Prefetch of accesses with an extreme stride might not be
+                worthwhile, either.  */
+             else if (PREFETCH_NO_EXTREME_STRIDE
+                      && stride > PREFETCH_EXTREME_STRIDE)
+               ignore_reason = "extreme stride";
+
+             /* Ignore GIVs with varying add values; we can't predict the
+                value for the next iteration.  */
+             else if (!loop_invariant_p (loop, iv->add_val))
+               ignore_reason = "giv has varying add value";
+
+             /* Ignore GIVs in the nested loops; they ought to have been
+                handled already.  */
+             else if (iv->maybe_multiple)
+               ignore_reason = "giv is in nested loop";
+           }
+
+         if (ignore_reason != NULL)
+           {
+             if (loop_dump_stream)
+               fprintf (loop_dump_stream,
+                        "Prefetch: ignoring giv at %d: %s.\n",
+                        INSN_UID (iv->insn), ignore_reason);
+             continue;
+           }
+
+         /* Determine the pointer to the basic array we are examining.  It is
+            the sum of the BIV's initial value and the GIV's add_val.  */
+         address = copy_rtx (iv->add_val);
+         temp = copy_rtx (bl->initial_value);
+
+         address = simplify_gen_binary (PLUS, Pmode, temp, address);
+         index = remove_constant_addition (&address);
+
+         d.mem_write = 0;
+         d.mem_address = *iv->location;
+
+         /* When the GIV is not always executed, we might be better off by
+            not dirtying the cache pages.  */
+         if (PREFETCH_CONDITIONAL || iv->always_executed)
+           note_stores (PATTERN (iv->insn), check_store, &d);
+         else
+           {
+             if (loop_dump_stream)
+               fprintf (loop_dump_stream, "Prefetch: Ignoring giv at %d: %s\n",
+                        INSN_UID (iv->insn), "in conditional code.");
+             continue;
+           }
+
+         /* Attempt to find another prefetch to the same array and see if we
+            can merge this one.  */
+         for (i = 0; i < num_prefetches; i++)
+           if (rtx_equal_for_prefetch_p (address, info[i].base_address)
+               && stride == info[i].stride)
+             {
+               /* In case both access same array (same location
+                  just with small difference in constant indexes), merge
+                  the prefetches.  Just do the later and the earlier will
+                  get prefetched from previous iteration.
+                  The artificial threshold should not be too small,
+                  but also not bigger than small portion of memory usually
+                  traversed by single loop.  */
+               if (index >= info[i].index
+                   && index - info[i].index < PREFETCH_EXTREME_DIFFERENCE)
+                 {
+                   info[i].write |= d.mem_write;
+                   info[i].bytes_accessed += size;
+                   info[i].index = index;
+                   info[i].giv = iv;
+                   info[i].class = bl;
+                   info[num_prefetches].base_address = address;
+                   add = 0;
+                   break;
+                 }
+
+               if (index < info[i].index
+                   && info[i].index - index < PREFETCH_EXTREME_DIFFERENCE)
+                 {
+                   info[i].write |= d.mem_write;
+                   info[i].bytes_accessed += size;
+                   add = 0;
+                   break;
+                 }
+             }
+
+         /* Merging failed.  */
+         if (add)
+           {
+             info[num_prefetches].giv = iv;
+             info[num_prefetches].class = bl;
+             info[num_prefetches].index = index;
+             info[num_prefetches].stride = stride;
+             info[num_prefetches].base_address = address;
+             info[num_prefetches].write = d.mem_write;
+             info[num_prefetches].bytes_accessed = size;
+             num_prefetches++;
+             if (num_prefetches >= MAX_PREFETCHES)
+               {
+                 if (loop_dump_stream)
+                   fprintf (loop_dump_stream,
+                            "Maximal number of prefetches exceeded.\n");
+                 return;
+               }
+           }
+       }
+    }
+
+  for (i = 0; i < num_prefetches; i++)
+    {
+      int density;
+
+      /* Attempt to calculate the total number of bytes fetched by all
+        iterations of the loop.  Avoid overflow.  */
+      if (LOOP_INFO (loop)->n_iterations
+         && ((unsigned HOST_WIDE_INT) (0xffffffff / info[i].stride)
+             >= LOOP_INFO (loop)->n_iterations))
+       info[i].total_bytes = info[i].stride * LOOP_INFO (loop)->n_iterations;
+      else
+       info[i].total_bytes = 0xffffffff;
+
+      density = info[i].bytes_accessed * 100 / info[i].stride;
+
+      /* Prefetch might be worthwhile only when the loads/stores are dense.  */
+      if (PREFETCH_ONLY_DENSE_MEM)
+       if (density * 256 > PREFETCH_DENSE_MEM * 100
+           && (info[i].total_bytes / PREFETCH_BLOCK
+               >= PREFETCH_BLOCKS_BEFORE_LOOP_MIN))
+         {
+           info[i].prefetch_before_loop = 1;
+           info[i].prefetch_in_loop
+             = (info[i].total_bytes / PREFETCH_BLOCK
+                > PREFETCH_BLOCKS_BEFORE_LOOP_MAX);
+         }
+       else
+         {
+           info[i].prefetch_in_loop = 0, info[i].prefetch_before_loop = 0;
+           if (loop_dump_stream)
+             fprintf (loop_dump_stream,
+                 "Prefetch: ignoring giv at %d: %d%% density is too low.\n",
+                      INSN_UID (info[i].giv->insn), density);
+         }
+      else
+       info[i].prefetch_in_loop = 1, info[i].prefetch_before_loop = 1;
+
+      /* Find how many prefetch instructions we'll use within the loop.  */
+      if (info[i].prefetch_in_loop != 0)
+       {
+         info[i].prefetch_in_loop = ((info[i].stride + PREFETCH_BLOCK - 1)
+                                 / PREFETCH_BLOCK);
+         num_real_prefetches += info[i].prefetch_in_loop;
+         if (info[i].write)
+           num_real_write_prefetches += info[i].prefetch_in_loop;
+       }
+    }
+
+  /* Determine how many iterations ahead to prefetch within the loop, based
+     on how many prefetches we currently expect to do within the loop.  */
+  if (num_real_prefetches != 0)
+    {
+      if ((ahead = SIMULTANEOUS_PREFETCHES / num_real_prefetches) == 0)
+       {
+         if (loop_dump_stream)
+           fprintf (loop_dump_stream,
+                    "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;
+       }
+    }
+  /* We'll also use AHEAD to determine how many prefetch instructions to
+     emit before a loop, so don't leave it zero.  */
+  if (ahead == 0)
+    ahead = PREFETCH_BLOCKS_BEFORE_LOOP_MAX;
+
+  for (i = 0; i < num_prefetches; i++)
+    {
+      /* Update if we've decided not to prefetch anything within the loop.  */
+      if (num_real_prefetches == 0)
+       info[i].prefetch_in_loop = 0;
+
+      /* Find how many prefetch instructions we'll use before the loop.  */
+      if (info[i].prefetch_before_loop != 0)
+       {
+         int n = info[i].total_bytes / PREFETCH_BLOCK;
+         if (n > ahead)
+           n = ahead;
+         info[i].prefetch_before_loop = n;
+         num_prefetches_before += n;
+         if (info[i].write)
+           num_write_prefetches_before += n;
+       }
+
+      if (loop_dump_stream)
+       {
+         if (info[i].prefetch_in_loop == 0
+             && info[i].prefetch_before_loop == 0)
+           continue;
+         fprintf (loop_dump_stream, "Prefetch insn: %d",
+                  INSN_UID (info[i].giv->insn));
+         fprintf (loop_dump_stream,
+                  "; 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,
+                  " 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
+                  "; 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");
+       }
+    }
+
+  if (num_real_prefetches + num_prefetches_before > 0)
+    {
+      /* Record that this loop uses prefetch instructions.  */
+      LOOP_INFO (loop)->has_prefetch = 1;
+
+      if (loop_dump_stream)
+       {
+         fprintf (loop_dump_stream, "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",
+                  num_prefetches_before, num_write_prefetches_before);
+       }
+    }
+
+  for (i = 0; i < num_prefetches; i++)
+    {
+      int y;
+
+      for (y = 0; y < info[i].prefetch_in_loop; y++)
+       {
+         rtx loc = copy_rtx (*info[i].giv->location);
+         rtx insn;
+         int bytes_ahead = PREFETCH_BLOCK * (ahead + y);
+         rtx before_insn = info[i].giv->insn;
+         rtx prev_insn = PREV_INSN (info[i].giv->insn);
+         rtx seq;
+
+         /* We can save some effort by offsetting the address on
+            architectures with offsettable memory references.  */
+         if (offsettable_address_p (0, VOIDmode, loc))
+           loc = plus_constant (loc, bytes_ahead);
+         else
+           {
+             rtx reg = gen_reg_rtx (Pmode);
+             loop_iv_add_mult_emit_before (loop, loc, const1_rtx,
+                                           GEN_INT (bytes_ahead), reg,
+                                           0, before_insn);
+             loc = reg;
+           }
+
+         start_sequence ();
+         /* Make sure the address operand is valid for prefetch.  */
+         if (! (*insn_data[(int)CODE_FOR_prefetch].operand[0].predicate)
+                 (loc, insn_data[(int)CODE_FOR_prefetch].operand[0].mode))
+           loc = force_reg (Pmode, loc);
+         emit_insn (gen_prefetch (loc, GEN_INT (info[i].write),
+                                  GEN_INT (3)));
+         seq = get_insns ();
+         end_sequence ();
+         emit_insn_before (seq, before_insn);
+
+         /* Check all insns emitted and record the new GIV
+            information.  */
+         insn = NEXT_INSN (prev_insn);
+         while (insn != before_insn)
+           {
+             insn = check_insn_for_givs (loop, insn,
+                                         info[i].giv->always_executed,
+                                         info[i].giv->maybe_multiple);
+             insn = NEXT_INSN (insn);
+           }
+       }
+
+      if (PREFETCH_BEFORE_LOOP)
+       {
+         /* Emit insns before the loop to fetch the first cache lines or,
+            if we're not prefetching within the loop, everything we expect
+            to need.  */
+         for (y = 0; y < info[i].prefetch_before_loop; y++)
+           {
+             rtx reg = gen_reg_rtx (Pmode);
+             rtx loop_start = loop->start;
+             rtx init_val = info[i].class->initial_value;
+             rtx add_val = simplify_gen_binary (PLUS, Pmode,
+                                                info[i].giv->add_val,
+                                                GEN_INT (y * PREFETCH_BLOCK));
+
+             /* Functions called by LOOP_IV_ADD_EMIT_BEFORE expect a
+                non-constant INIT_VAL to have the same mode as REG, which
+                in this case we know to be Pmode.  */
+             if (GET_MODE (init_val) != Pmode && !CONSTANT_P (init_val))
+               {
+                 rtx seq;
+
+                 start_sequence ();
+                 init_val = convert_to_mode (Pmode, init_val, 0);
+                 seq = get_insns ();
+                 end_sequence ();
+                 loop_insn_emit_before (loop, 0, loop_start, seq);
+               }
+             loop_iv_add_mult_emit_before (loop, init_val,
+                                           info[i].giv->mult_val,
+                                           add_val, reg, 0, loop_start);
+             emit_insn_before (gen_prefetch (reg, GEN_INT (info[i].write),
+                                             GEN_INT (3)),
+                               loop_start);
+           }
+       }
+    }
+
+  return;
+}
+\f
+/* A "basic induction variable" or biv is a pseudo reg that is set
+   (within this loop) only by incrementing or decrementing it.  */
+/* A "general induction variable" or giv is a pseudo reg whose
+   value is a linear function of a biv.  */
+
+/* Bivs are recognized by `basic_induction_var';
+   Givs by `general_induction_var'.  */
+
+/* Communication with routines called via `note_stores'.  */
+
+static rtx note_insn;
+
+/* Dummy register to have nonzero DEST_REG for DEST_ADDR type givs.  */
+
+static rtx addr_placeholder;
+
+/* ??? Unfinished optimizations, and possible future optimizations,
+   for the strength reduction code.  */
+
+/* ??? The interaction of biv elimination, and recognition of 'constant'
+   bivs, may cause problems.  */
+
+/* ??? Add heuristics so that DEST_ADDR strength reduction does not cause
+   performance problems.
+
+   Perhaps don't eliminate things that can be combined with an addressing
+   mode.  Find all givs that have the same biv, mult_val, and add_val;
+   then for each giv, check to see if its only use dies in a following
+   memory address.  If so, generate a new memory address and check to see
+   if it is valid.   If it is valid, then store the modified memory address,
+   otherwise, mark the giv as not done so that it will get its own iv.  */
+
+/* ??? Could try to optimize branches when it is known that a biv is always
+   positive.  */
+
+/* ??? When replace a biv in a compare insn, we should replace with closest
+   giv so that an optimized branch can still be recognized by the combiner,
+   e.g. the VAX acb insn.  */
+
+/* ??? Many of the checks involving uid_luid could be simplified if regscan
+   was rerun in loop_optimize whenever a register was added or moved.
+   Also, some of the optimizations could be a little less conservative.  */
+\f
+/* Scan the loop body and call FNCALL for each insn.  In the addition to the
+   LOOP and INSN parameters pass MAYBE_MULTIPLE and NOT_EVERY_ITERATION to the
+   callback.
+
+   NOT_EVERY_ITERATION is 1 if current insn is not known to be executed at
+   least once for every loop iteration except for the last one.
+
+   MAYBE_MULTIPLE is 1 if current insn may be executed more than once for every
+   loop iteration.
+ */
+void
+for_each_insn_in_loop (loop, fncall)
+     struct loop *loop;
+     loop_insn_callback fncall;
+{
+  int not_every_iteration = 0;
+  int maybe_multiple = 0;
+  int past_loop_latch = 0;
+  int loop_depth = 0;
+  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 (prev_nonnote_insn (loop->scan_start) != prev_nonnote_insn (loop->start))
+    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);
+       p != NULL_RTX;
+       p = next_insn_in_loop (loop, p))
+    {
+      p = fncall (loop, p, not_every_iteration, maybe_multiple);
+
+      /* Past CODE_LABEL, we get to insns that may be executed multiple
+         times.  The only way we can be sure that they can't is if every
+         jump insn between here and the end of the loop either
+         returns, exits the loop, is a jump to a location that is still
+         behind the label, or is a jump to the loop start.  */
+
+      if (GET_CODE (p) == CODE_LABEL)
+       {
+         rtx insn = p;
+
+         maybe_multiple = 0;
+
+         while (1)
+           {
+             insn = NEXT_INSN (insn);
+             if (insn == loop->scan_start)
+               break;
+             if (insn == loop->end)
+               {
+                 if (loop->top != 0)
+                   insn = loop->top;
                  else
                    break;
                  if (insn == loop->scan_start)
@@ -3554,9 +4434,9 @@ for_each_insn_in_loop (loop, fncall)
          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)))))
+              && ((NEXT_INSN (NEXT_INSN (p)) == loop->end
+                   && any_uncondjump_p (p))
+                  || (NEXT_INSN (p) == loop->end && any_condjump_p (p)))))
        {
          rtx label = 0;
 
@@ -3612,36 +4492,671 @@ for_each_insn_in_loop (loop, fncall)
          a jump to the top of the loop, then we know these insns will be
          executed each iteration.  */
 
-      if (not_every_iteration
-         && !past_loop_latch
-         && GET_CODE (p) == CODE_LABEL
-         && no_labels_between_p (p, loop->end)
-         && loop_insn_first_p (p, loop->cont))
-       not_every_iteration = 0;
+      if (not_every_iteration
+         && !past_loop_latch
+         && GET_CODE (p) == CODE_LABEL
+         && no_labels_between_p (p, loop->end)
+         && loop_insn_first_p (p, loop->cont))
+       not_every_iteration = 0;
+    }
+}
+\f
+static void
+loop_bivs_find (loop)
+     struct loop *loop;
+{
+  struct loop_regs *regs = LOOP_REGS (loop);
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  /* Temporary list pointers for traversing ivs->list.  */
+  struct iv_class *bl, **backbl;
+
+  ivs->list = 0;
+
+  for_each_insn_in_loop (loop, check_insn_for_bivs);
+
+  /* Scan ivs->list to remove all regs that proved not to be bivs.
+     Make a sanity check against regs->n_times_set.  */
+  for (backbl = &ivs->list, bl = *backbl; bl; bl = bl->next)
+    {
+      if (REG_IV_TYPE (ivs, bl->regno) != BASIC_INDUCT
+         /* Above happens if register modified by subreg, etc.  */
+         /* Make sure it is not recognized as a basic induction var: */
+         || regs->array[bl->regno].n_times_set != bl->biv_count
+         /* If never incremented, it is invariant that we decided not to
+            move.  So leave it alone.  */
+         || ! bl->incremented)
+       {
+         if (loop_dump_stream)
+           fprintf (loop_dump_stream, "Biv %d: discarded, %s\n",
+                    bl->regno,
+                    (REG_IV_TYPE (ivs, bl->regno) != BASIC_INDUCT
+                     ? "not induction variable"
+                     : (! bl->incremented ? "never incremented"
+                        : "count error")));
+
+         REG_IV_TYPE (ivs, bl->regno) = NOT_BASIC_INDUCT;
+         *backbl = bl->next;
+       }
+      else
+       {
+         backbl = &bl->next;
+
+         if (loop_dump_stream)
+           fprintf (loop_dump_stream, "Biv %d: verified\n", bl->regno);
+       }
+    }
+}
+
+
+/* Determine how BIVS are initialized by looking through pre-header
+   extended basic block.  */
+static void
+loop_bivs_init_find (loop)
+     struct loop *loop;
+{
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  /* Temporary list pointers for traversing ivs->list.  */
+  struct iv_class *bl;
+  int call_seen;
+  rtx p;
+
+  /* Find initial value for each biv by searching backwards from loop_start,
+     halting at first label.  Also record any test condition.  */
+
+  call_seen = 0;
+  for (p = loop->start; p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
+    {
+      rtx test;
+
+      note_insn = p;
+
+      if (GET_CODE (p) == CALL_INSN)
+       call_seen = 1;
+
+      if (INSN_P (p))
+       note_stores (PATTERN (p), record_initial, ivs);
+
+      /* Record any test of a biv that branches around the loop if no store
+        between it and the start of loop.  We only care about tests with
+        constants and registers and only certain of those.  */
+      if (GET_CODE (p) == JUMP_INSN
+         && JUMP_LABEL (p) != 0
+         && next_real_insn (JUMP_LABEL (p)) == next_real_insn (loop->end)
+         && (test = get_condition_for_loop (loop, p)) != 0
+         && GET_CODE (XEXP (test, 0)) == REG
+         && REGNO (XEXP (test, 0)) < max_reg_before_loop
+         && (bl = REG_IV_CLASS (ivs, REGNO (XEXP (test, 0)))) != 0
+         && valid_initial_value_p (XEXP (test, 1), p, call_seen, loop->start)
+         && bl->init_insn == 0)
+       {
+         /* If an NE test, we have an initial value!  */
+         if (GET_CODE (test) == NE)
+           {
+             bl->init_insn = p;
+             bl->init_set = gen_rtx_SET (VOIDmode,
+                                         XEXP (test, 0), XEXP (test, 1));
+           }
+         else
+           bl->initial_test = test;
+       }
+    }
+}
+
+
+/* Look at the each biv and see if we can say anything better about its
+   initial value from any initializing insns set up above.  (This is done
+   in two passes to avoid missing SETs in a PARALLEL.)  */
+static void
+loop_bivs_check (loop)
+     struct loop *loop;
+{
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  /* Temporary list pointers for traversing ivs->list.  */
+  struct iv_class *bl;
+  struct iv_class **backbl;
+
+  for (backbl = &ivs->list; (bl = *backbl); backbl = &bl->next)
+    {
+      rtx src;
+      rtx note;
+
+      if (! bl->init_insn)
+       continue;
+
+      /* IF INIT_INSN has a REG_EQUAL or REG_EQUIV note and the value
+        is a constant, use the value of that.  */
+      if (((note = find_reg_note (bl->init_insn, REG_EQUAL, 0)) != NULL
+          && CONSTANT_P (XEXP (note, 0)))
+         || ((note = find_reg_note (bl->init_insn, REG_EQUIV, 0)) != NULL
+             && CONSTANT_P (XEXP (note, 0))))
+       src = XEXP (note, 0);
+      else
+       src = SET_SRC (bl->init_set);
+
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Biv %d: initialized at insn %d: initial value ",
+                bl->regno, INSN_UID (bl->init_insn));
+
+      if ((GET_MODE (src) == GET_MODE (regno_reg_rtx[bl->regno])
+          || GET_MODE (src) == VOIDmode)
+         && valid_initial_value_p (src, bl->init_insn,
+                                   LOOP_INFO (loop)->pre_header_has_call,
+                                   loop->start))
+       {
+         bl->initial_value = src;
+
+         if (loop_dump_stream)
+           {
+             print_simple_rtl (loop_dump_stream, src);
+             fputc ('\n', loop_dump_stream);
+           }
+       }
+      /* 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");
+    }
+}
+
+
+/* Search the loop for general induction variables.  */
+
+static void
+loop_givs_find (loop)
+     struct loop* loop;
+{
+  for_each_insn_in_loop (loop, check_insn_for_givs);
+}
+
+
+/* For each giv for which we still don't know whether or not it is
+   replaceable, check to see if it is replaceable because its final value
+   can be calculated.  */
+
+static void
+loop_givs_check (loop)
+     struct loop *loop;
+{
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  struct iv_class *bl;
+
+  for (bl = ivs->list; bl; bl = bl->next)
+    {
+      struct induction *v;
+
+      for (v = bl->giv; v; v = v->next_iv)
+       if (! v->replaceable && ! v->not_replaceable)
+         check_final_value (loop, v);
+    }
+}
+
+
+/* Return nonzero if it is possible to eliminate the biv BL provided
+   all givs are reduced.  This is possible if either the reg is not
+   used outside the loop, or we can compute what its final value will
+   be.  */
+
+static int
+loop_biv_eliminable_p (loop, bl, threshold, insn_count)
+     struct loop *loop;
+     struct iv_class *bl;
+     int threshold;
+     int insn_count;
+{
+  /* For architectures with a decrement_and_branch_until_zero insn,
+     don't do this if we put a REG_NONNEG note on the endtest for this
+     biv.  */
+
+#ifdef HAVE_decrement_and_branch_until_zero
+  if (bl->nonneg)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Cannot eliminate nonneg biv %d.\n", bl->regno);
+      return 0;
+    }
+#endif
+
+  /* Check that biv is used outside loop or if it has a final value.
+     Compare against bl->init_insn rather than loop->start.  We aren't
+     concerned with any uses of the biv between init_insn and
+     loop->start since these won't be affected by the value of the biv
+     elsewhere in the function, so long as init_insn doesn't use the
+     biv itself.  */
+
+  if ((REGNO_LAST_LUID (bl->regno) < INSN_LUID (loop->end)
+       && bl->init_insn
+       && INSN_UID (bl->init_insn) < max_uid_for_loop
+       && REGNO_FIRST_LUID (bl->regno) >= INSN_LUID (bl->init_insn)
+       && ! reg_mentioned_p (bl->biv->dest_reg, SET_SRC (bl->init_set)))
+      || (bl->final_value = final_biv_value (loop, bl)))
+    return maybe_eliminate_biv (loop, bl, 0, threshold,        insn_count);
+
+  if (loop_dump_stream)
+    {
+      fprintf (loop_dump_stream,
+              "Cannot eliminate biv %d.\n",
+              bl->regno);
+      fprintf (loop_dump_stream,
+              "First use: insn %d, last use: insn %d.\n",
+              REGNO_FIRST_UID (bl->regno),
+              REGNO_LAST_UID (bl->regno));
+    }
+  return 0;
+}
+
+
+/* Reduce each giv of BL that we have decided to reduce.  */
+
+static void
+loop_givs_reduce (loop, bl)
+     struct loop *loop;
+     struct iv_class *bl;
+{
+  struct induction *v;
+
+  for (v = bl->giv; v; v = v->next_iv)
+    {
+      struct induction *tv;
+      if (! v->ignore && v->same == 0)
+       {
+         int auto_inc_opt = 0;
+
+         /* If the code for derived givs immediately below has already
+            allocated a new_reg, we must keep it.  */
+         if (! v->new_reg)
+           v->new_reg = gen_reg_rtx (v->mode);
+
+#ifdef AUTO_INC_DEC
+         /* If the target has auto-increment addressing modes, and
+            this is an address giv, then try to put the increment
+            immediately after its use, so that flow can create an
+            auto-increment addressing mode.  */
+         if (v->giv_type == DEST_ADDR && bl->biv_count == 1
+             && bl->biv->always_executed && ! bl->biv->maybe_multiple
+             /* We don't handle reversed biv's because bl->biv->insn
+                does not have a valid INSN_LUID.  */
+             && ! bl->reversed
+             && v->always_executed && ! v->maybe_multiple
+             && INSN_UID (v->insn) < max_uid_for_loop)
+           {
+             /* If other giv's have been combined with this one, then
+                this will work only if all uses of the other giv's occur
+                before this giv's insn.  This is difficult to check.
+
+                We simplify this by looking for the common case where
+                there is one DEST_REG giv, and this giv's insn is the
+                last use of the dest_reg of that DEST_REG giv.  If the
+                increment occurs after the address giv, then we can
+                perform the optimization.  (Otherwise, the increment
+                would have to go before other_giv, and we would not be
+                able to combine it with the address giv to get an
+                auto-inc address.)  */
+             if (v->combined_with)
+               {
+                 struct induction *other_giv = 0;
+
+                 for (tv = bl->giv; tv; tv = tv->next_iv)
+                   if (tv->same == v)
+                     {
+                       if (other_giv)
+                         break;
+                       else
+                         other_giv = tv;
+                     }
+                 if (! tv && other_giv
+                     && REGNO (other_giv->dest_reg) < max_reg_before_loop
+                     && (REGNO_LAST_UID (REGNO (other_giv->dest_reg))
+                         == INSN_UID (v->insn))
+                     && INSN_LUID (v->insn) < INSN_LUID (bl->biv->insn))
+                   auto_inc_opt = 1;
+               }
+             /* Check for case where increment is before the address
+                giv.  Do this test in "loop order".  */
+             else if ((INSN_LUID (v->insn) > INSN_LUID (bl->biv->insn)
+                       && (INSN_LUID (v->insn) < INSN_LUID (loop->scan_start)
+                           || (INSN_LUID (bl->biv->insn)
+                               > INSN_LUID (loop->scan_start))))
+                      || (INSN_LUID (v->insn) < INSN_LUID (loop->scan_start)
+                          && (INSN_LUID (loop->scan_start)
+                              < INSN_LUID (bl->biv->insn))))
+               auto_inc_opt = -1;
+             else
+               auto_inc_opt = 1;
+
+#ifdef HAVE_cc0
+             {
+               rtx prev;
+
+               /* We can't put an insn immediately after one setting
+                  cc0, or immediately before one using cc0.  */
+               if ((auto_inc_opt == 1 && sets_cc0_p (PATTERN (v->insn)))
+                   || (auto_inc_opt == -1
+                       && (prev = prev_nonnote_insn (v->insn)) != 0
+                       && INSN_P (prev)
+                       && sets_cc0_p (PATTERN (prev))))
+                 auto_inc_opt = 0;
+             }
+#endif
+
+             if (auto_inc_opt)
+               v->auto_inc_opt = 1;
+           }
+#endif
+
+         /* For each place where the biv is incremented, add an insn
+            to increment the new, reduced reg for the giv.  */
+         for (tv = bl->biv; tv; tv = tv->next_iv)
+           {
+             rtx insert_before;
+
+             /* Skip if location is the same as a previous one.  */
+             if (tv->same)
+               continue;
+             if (! auto_inc_opt)
+               insert_before = NEXT_INSN (tv->insn);
+             else if (auto_inc_opt == 1)
+               insert_before = NEXT_INSN (v->insn);
+             else
+               insert_before = v->insn;
+
+             if (tv->mult_val == const1_rtx)
+               loop_iv_add_mult_emit_before (loop, tv->add_val, v->mult_val,
+                                             v->new_reg, v->new_reg,
+                                             0, insert_before);
+             else /* tv->mult_val == const0_rtx */
+               /* A multiply is acceptable here
+                  since this is presumed to be seldom executed.  */
+               loop_iv_add_mult_emit_before (loop, tv->add_val, v->mult_val,
+                                             v->add_val, v->new_reg,
+                                             0, insert_before);
+           }
+
+         /* Add code at loop start to initialize giv's reduced reg.  */
+
+         loop_iv_add_mult_hoist (loop,
+                                 extend_value_for_giv (v, bl->initial_value),
+                                 v->mult_val, v->add_val, v->new_reg);
+       }
+    }
+}
+
+
+/* Check for givs whose first use is their definition and whose
+   last use is the definition of another giv.  If so, it is likely
+   dead and should not be used to derive another giv nor to
+   eliminate a biv.  */
+
+static void
+loop_givs_dead_check (loop, bl)
+     struct loop *loop ATTRIBUTE_UNUSED;
+     struct iv_class *bl;
+{
+  struct induction *v;
+
+  for (v = bl->giv; v; v = v->next_iv)
+    {
+      if (v->ignore
+         || (v->same && v->same->ignore))
+       continue;
+
+      if (v->giv_type == DEST_REG
+         && REGNO_FIRST_UID (REGNO (v->dest_reg)) == INSN_UID (v->insn))
+       {
+         struct induction *v1;
+
+         for (v1 = bl->giv; v1; v1 = v1->next_iv)
+           if (REGNO_LAST_UID (REGNO (v->dest_reg)) == INSN_UID (v1->insn))
+             v->maybe_dead = 1;
+       }
+    }
+}
+
+
+static void
+loop_givs_rescan (loop, bl, reg_map)
+     struct loop *loop;
+     struct iv_class *bl;
+     rtx *reg_map;
+{
+  struct induction *v;
+
+  for (v = bl->giv; v; v = v->next_iv)
+    {
+      if (v->same && v->same->ignore)
+       v->ignore = 1;
+
+      if (v->ignore)
+       continue;
+
+      /* Update expression if this was combined, in case other giv was
+        replaced.  */
+      if (v->same)
+       v->new_reg = replace_rtx (v->new_reg,
+                                 v->same->dest_reg, v->same->new_reg);
+
+      /* See if this register is known to be a pointer to something.  If
+        so, see if we can find the alignment.  First see if there is a
+        destination register that is a pointer.  If so, this shares the
+        alignment too.  Next see if we can deduce anything from the
+        computational information.  If not, and this is a DEST_ADDR
+        giv, at least we know that it's a pointer, though we don't know
+        the alignment.  */
+      if (GET_CODE (v->new_reg) == REG
+         && v->giv_type == DEST_REG
+         && REG_POINTER (v->dest_reg))
+       mark_reg_pointer (v->new_reg,
+                         REGNO_POINTER_ALIGN (REGNO (v->dest_reg)));
+      else if (GET_CODE (v->new_reg) == REG
+              && REG_POINTER (v->src_reg))
+       {
+         unsigned int align = REGNO_POINTER_ALIGN (REGNO (v->src_reg));
+
+         if (align == 0
+             || GET_CODE (v->add_val) != CONST_INT
+             || INTVAL (v->add_val) % (align / BITS_PER_UNIT) != 0)
+           align = 0;
+
+         mark_reg_pointer (v->new_reg, align);
+       }
+      else if (GET_CODE (v->new_reg) == REG
+              && GET_CODE (v->add_val) == REG
+              && REG_POINTER (v->add_val))
+       {
+         unsigned int align = REGNO_POINTER_ALIGN (REGNO (v->add_val));
+
+         if (align == 0 || GET_CODE (v->mult_val) != CONST_INT
+             || INTVAL (v->mult_val) % (align / BITS_PER_UNIT) != 0)
+           align = 0;
+
+         mark_reg_pointer (v->new_reg, align);
+       }
+      else if (GET_CODE (v->new_reg) == REG && v->giv_type == DEST_ADDR)
+       mark_reg_pointer (v->new_reg, 0);
+
+      if (v->giv_type == DEST_ADDR)
+       /* Store reduced reg as the address in the memref where we found
+          this giv.  */
+       validate_change (v->insn, v->location, v->new_reg, 0);
+      else if (v->replaceable)
+       {
+         reg_map[REGNO (v->dest_reg)] = v->new_reg;
+       }
+      else
+       {
+         rtx original_insn = v->insn;
+         rtx note;
+
+         /* Not replaceable; emit an insn to set the original giv reg from
+            the reduced giv, same as above.  */
+         v->insn = loop_insn_emit_after (loop, 0, original_insn,
+                                         gen_move_insn (v->dest_reg,
+                                                        v->new_reg));
+
+         /* The original insn may have a REG_EQUAL note.  This note is
+            now incorrect and may result in invalid substitutions later.
+            The original insn is dead, but may be part of a libcall
+            sequence, which doesn't seem worth the bother of handling.  */
+         note = find_reg_note (original_insn, REG_EQUAL, NULL_RTX);
+         if (note)
+           remove_note (original_insn, note);
+       }
+
+      /* When a loop is reversed, givs which depend on the reversed
+        biv, and which are live outside the loop, must be set to their
+        correct final value.  This insn is only needed if the giv is
+        not replaceable.  The correct final value is the same as the
+        value that the giv starts the reversed loop with.  */
+      if (bl->reversed && ! v->replaceable)
+       loop_iv_add_mult_sink (loop,
+                              extend_value_for_giv (v, bl->initial_value),
+                              v->mult_val, v->add_val, v->dest_reg);
+      else if (v->final_value)
+       loop_insn_sink_or_swim (loop,
+                               gen_load_of_final_value (v->dest_reg,
+                                                        v->final_value));
+
+      if (loop_dump_stream)
+       {
+         fprintf (loop_dump_stream, "giv at %d reduced to ",
+                  INSN_UID (v->insn));
+         print_simple_rtl (loop_dump_stream, v->new_reg);
+         fprintf (loop_dump_stream, "\n");
+       }
+    }
+}
+
+
+static int
+loop_giv_reduce_benefit (loop, bl, v, test_reg)
+     struct loop *loop ATTRIBUTE_UNUSED;
+     struct iv_class *bl;
+     struct induction *v;
+     rtx test_reg;
+{
+  int add_cost;
+  int benefit;
+
+  benefit = v->benefit;
+  PUT_MODE (test_reg, v->mode);
+  add_cost = iv_add_mult_cost (bl->biv->add_val, v->mult_val,
+                              test_reg, test_reg);
+
+  /* Reduce benefit if not replaceable, since we will insert a
+     move-insn to replace the insn that calculates this giv.  Don't do
+     this unless the giv is a user variable, since it will often be
+     marked non-replaceable because of the duplication of the exit
+     code outside the loop.  In such a case, the copies we insert are
+     dead and will be deleted.  So they don't have a cost.  Similar
+     situations exist.  */
+  /* ??? The new final_[bg]iv_value code does a much better job of
+     finding replaceable giv's, and hence this code may no longer be
+     necessary.  */
+  if (! v->replaceable && ! bl->eliminable
+      && REG_USERVAR_P (v->dest_reg))
+    benefit -= copy_cost;
+
+  /* Decrease the benefit to count the add-insns that we will insert
+     to increment the reduced reg for the giv.  ??? This can
+     overestimate the run-time cost of the additional insns, e.g. if
+     there are multiple basic blocks that increment the biv, but only
+     one of these blocks is executed during each iteration.  There is
+     no good way to detect cases like this with the current structure
+     of the loop optimizer.  This code is more accurate for
+     determining code size than run-time benefits.  */
+  benefit -= add_cost * bl->biv_count;
+
+  /* Decide whether to strength-reduce this giv or to leave the code
+     unchanged (recompute it from the biv each time it is used).  This
+     decision can be made independently for each giv.  */
+
+#ifdef AUTO_INC_DEC
+  /* Attempt to guess whether autoincrement will handle some of the
+     new add insns; if so, increase BENEFIT (undo the subtraction of
+     add_cost that was done above).  */
+  if (v->giv_type == DEST_ADDR
+      /* Increasing the benefit is risky, since this is only a guess.
+        Avoid increasing register pressure in cases where there would
+        be no other benefit from reducing this giv.  */
+      && benefit > 0
+      && GET_CODE (v->mult_val) == CONST_INT)
+    {
+      int size = GET_MODE_SIZE (GET_MODE (v->mem));
+
+      if (HAVE_POST_INCREMENT
+         && INTVAL (v->mult_val) == size)
+       benefit += add_cost * bl->biv_count;
+      else if (HAVE_PRE_INCREMENT
+              && INTVAL (v->mult_val) == size)
+       benefit += add_cost * bl->biv_count;
+      else if (HAVE_POST_DECREMENT
+              && -INTVAL (v->mult_val) == size)
+       benefit += add_cost * bl->biv_count;
+      else if (HAVE_PRE_DECREMENT
+              && -INTVAL (v->mult_val) == size)
+       benefit += add_cost * bl->biv_count;
+    }
+#endif
+
+  return benefit;
+}
+
+
+/* Free IV structures for LOOP.  */
+
+static void
+loop_ivs_free (loop)
+     struct loop *loop;
+{
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  struct iv_class *iv = ivs->list;
+
+  free (ivs->regs);
+
+  while (iv)
+    {
+      struct iv_class *next = iv->next;
+      struct induction *induction;
+      struct induction *next_induction;
+
+      for (induction = iv->biv; induction; induction = next_induction)
+       {
+         next_induction = induction->next_iv;
+         free (induction);
+       }
+      for (induction = iv->giv; induction; induction = next_induction)
+       {
+         next_induction = induction->next_iv;
+         free (induction);
+       }
+
+      free (iv);
+      iv = next;
     }
 }
-\f
+
+
 /* Perform strength reduction and induction variable elimination.
 
    Pseudo registers created during this function will be beyond the
-   last valid index in several tables including regs->n_times_set and
-   regno_last_uid.  This does not cause a problem here, because the
-   added registers cannot be givs outside of their loop, and hence
-   will never be reconsidered.  But scan_loop must check regnos to
-   make sure they are in bounds.  */
+   last valid index in several tables including
+   REGS->ARRAY[I].N_TIMES_SET and REGNO_LAST_UID.  This does not cause a
+   problem here, because the added registers cannot be givs outside of
+   their loop, and hence will never be reconsidered.  But scan_loop
+   must check regnos to make sure they are in bounds.  */
 
 static void
-strength_reduce (loop, insn_count, flags)
+strength_reduce (loop, flags)
      struct loop *loop;
-     int insn_count;
      int flags;
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
   struct loop_ivs *ivs = LOOP_IVS (loop);
   rtx p;
-  /* Temporary list pointers for traversing ivs->loop_iv_list.  */
-  struct iv_class *bl, **backbl;
+  /* Temporary list pointer for traversing ivs->list.  */
+  struct iv_class *bl;
   /* Ratio of extra register life span we can justify
      for saving an instruction.  More if loop doesn't call subroutines
      since in that case saving an insn makes more difference
@@ -3651,194 +5166,57 @@ strength_reduce (loop, insn_count, flags)
   /* Map of pseudo-register replacements.  */
   rtx *reg_map = NULL;
   int reg_map_size;
-  int call_seen;
-  rtx test;
-  rtx end_insert_before;
   int unrolled_insn_copies = 0;
-  rtx loop_start = loop->start;
-  rtx loop_end = loop->end;
   rtx test_reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
+  int insn_count = count_insns_in_loop (loop);
 
-  VARRAY_INT_INIT (ivs->reg_iv_type, max_reg_before_loop, "reg_iv_type");
-  VARRAY_GENERIC_PTR_INIT (ivs->reg_iv_info, max_reg_before_loop, "reg_iv_info");
-  ivs->reg_biv_class = (struct iv_class **)
-    xcalloc (max_reg_before_loop, sizeof (struct iv_class *));
-
-  ivs->loop_iv_list = 0;
   addr_placeholder = gen_reg_rtx (Pmode);
 
-  /* Save insn immediately after the loop_end.  Insns inserted after loop_end
-     must be put before this insn, so that they will appear in the right
-     order (i.e. loop order).
-
-     If loop_end is the end of the current function, then emit a
-     NOTE_INSN_DELETED after loop_end and set end_insert_before to the
-     dummy note insn.  */
-  if (NEXT_INSN (loop_end) != 0)
-    end_insert_before = NEXT_INSN (loop_end);
-  else
-    end_insert_before = emit_note_after (NOTE_INSN_DELETED, loop_end);
-
-  for_each_insn_in_loop (loop, check_insn_for_bivs);
-
-  /* Scan ivs->loop_iv_list to remove all regs that proved not to be bivs.
-     Make a sanity check against regs->n_times_set.  */
-  for (backbl = &ivs->loop_iv_list, bl = *backbl; bl; bl = bl->next)
-    {
-      if (REG_IV_TYPE (ivs, bl->regno) != BASIC_INDUCT
-         /* Above happens if register modified by subreg, etc.  */
-         /* Make sure it is not recognized as a basic induction var: */
-         || VARRAY_INT (regs->n_times_set, bl->regno) != bl->biv_count
-         /* If never incremented, it is invariant that we decided not to
-            move.  So leave it alone.  */
-         || ! bl->incremented)
-       {
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream, "Reg %d: biv discarded, %s\n",
-                    bl->regno,
-                    (REG_IV_TYPE (ivs, bl->regno) != BASIC_INDUCT
-                     ? "not induction variable"
-                     : (! bl->incremented ? "never incremented"
-                        : "count error")));
-
-         REG_IV_TYPE (ivs, bl->regno) = NOT_BASIC_INDUCT;
-         *backbl = bl->next;
-       }
-      else
-       {
-         backbl = &bl->next;
+  ivs->n_regs = max_reg_before_loop;
+  ivs->regs = (struct iv *) xcalloc (ivs->n_regs, sizeof (struct iv));
 
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream, "Reg %d: biv verified\n", bl->regno);
-       }
-    }
+  /* Find all BIVs in loop.  */
+  loop_bivs_find (loop);
 
   /* Exit if there are no bivs.  */
-  if (! ivs->loop_iv_list)
+  if (! ivs->list)
     {
       /* Can still unroll the loop anyways, but indicate that there is no
         strength reduction info available.  */
       if (flags & LOOP_UNROLL)
-       unroll_loop (loop, insn_count, end_insert_before, 0);
+       unroll_loop (loop, insn_count, 0);
 
-      goto egress;
+      loop_ivs_free (loop);
+      return;
     }
 
-  /* Find initial value for each biv by searching backwards from loop_start,
-     halting at first label.  Also record any test condition.  */
-
-  call_seen = 0;
-  for (p = loop_start; p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
-    {
-      note_insn = p;
-
-      if (GET_CODE (p) == CALL_INSN)
-       call_seen = 1;
-
-      if (INSN_P (p))
-       note_stores (PATTERN (p), record_initial, ivs);
-
-      /* Record any test of a biv that branches around the loop if no store
-        between it and the start of loop.  We only care about tests with
-        constants and registers and only certain of those.  */
-      if (GET_CODE (p) == JUMP_INSN
-         && JUMP_LABEL (p) != 0
-         && next_real_insn (JUMP_LABEL (p)) == next_real_insn (loop_end)
-         && (test = get_condition_for_loop (loop, p)) != 0
-         && GET_CODE (XEXP (test, 0)) == REG
-         && REGNO (XEXP (test, 0)) < max_reg_before_loop
-         && (bl = ivs->reg_biv_class[REGNO (XEXP (test, 0))]) != 0
-         && valid_initial_value_p (XEXP (test, 1), p, call_seen, loop_start)
-         && bl->init_insn == 0)
-       {
-         /* If an NE test, we have an initial value!  */
-         if (GET_CODE (test) == NE)
-           {
-             bl->init_insn = p;
-             bl->init_set = gen_rtx_SET (VOIDmode,
-                                         XEXP (test, 0), XEXP (test, 1));
-           }
-         else
-           bl->initial_test = test;
-       }
-    }
+  /* Determine how BIVS are initialized by looking through pre-header
+     extended basic block.  */
+  loop_bivs_init_find (loop);
 
   /* Look at the each biv and see if we can say anything better about its
-     initial value from any initializing insns set up above.  (This is done
-     in two passes to avoid missing SETs in a PARALLEL.)  */
-  for (backbl = &ivs->loop_iv_list; (bl = *backbl); backbl = &bl->next)
-    {
-      rtx src;
-      rtx note;
-
-      if (! bl->init_insn)
-       continue;
-
-      /* IF INIT_INSN has a REG_EQUAL or REG_EQUIV note and the value
-        is a constant, use the value of that.  */
-      if (((note = find_reg_note (bl->init_insn, REG_EQUAL, 0)) != NULL
-          && CONSTANT_P (XEXP (note, 0)))
-         || ((note = find_reg_note (bl->init_insn, REG_EQUIV, 0)) != NULL
-             && CONSTANT_P (XEXP (note, 0))))
-       src = XEXP (note, 0);
-      else
-       src = SET_SRC (bl->init_set);
-
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
-                "Biv %d initialized at insn %d: initial value ",
-                bl->regno, INSN_UID (bl->init_insn));
-
-      if ((GET_MODE (src) == GET_MODE (regno_reg_rtx[bl->regno])
-          || GET_MODE (src) == VOIDmode)
-         && valid_initial_value_p (src, bl->init_insn, call_seen, loop_start))
-       {
-         bl->initial_value = src;
-
-         if (loop_dump_stream)
-           {
-             if (GET_CODE (src) == CONST_INT)
-               {
-                 fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (src));
-                 fputc ('\n', loop_dump_stream);
-               }
-             else
-               {
-                 print_rtl (loop_dump_stream, src);
-                 fprintf (loop_dump_stream, "\n");
-               }
-           }
-       }
-      /* 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");
-    }
+     initial value from any initializing insns set up above.  */
+  loop_bivs_check (loop);
 
   /* Search the loop for general induction variables.  */
-
-  for_each_insn_in_loop (loop, check_insn_for_givs);
+  loop_givs_find (loop);
 
   /* Try to calculate and save the number of loop iterations.  This is
      set to zero if the actual number can not be calculated.  This must
      be called after all giv's have been identified, since otherwise it may
      fail if the iteration variable is a giv.  */
-
   loop_iterations (loop);
 
+#ifdef HAVE_prefetch
+  if (flags & LOOP_PREFETCH)
+    emit_prefetch_instructions (loop);
+#endif
+
   /* Now for each giv for which we still don't know whether or not it is
      replaceable, check to see if it is replaceable because its final value
      can be calculated.  This must be done after loop_iterations is called,
      so that final_giv_value will work correctly.  */
-
-  for (bl = ivs->loop_iv_list; bl; bl = bl->next)
-    {
-      struct induction *v;
-
-      for (v = bl->giv; v; v = v->next_iv)
-       if (! v->replaceable && ! v->not_replaceable)
-         check_final_value (loop, v);
-    }
+  loop_givs_check (loop);
 
   /* Try to prove that the loop counter variable (if any) is always
      nonnegative; if so, record that fact with a REG_NONNEG note
@@ -3848,148 +5226,44 @@ strength_reduce (loop, insn_count, flags)
   /* Create reg_map to hold substitutions for replaceable giv regs.
      Some givs might have been made from biv increments, so look at
      ivs->reg_iv_type for a suitable size.  */
-  reg_map_size = ivs->reg_iv_type->num_elements;
+  reg_map_size = ivs->n_regs;
   reg_map = (rtx *) xcalloc (reg_map_size, sizeof (rtx));
 
   /* Examine each iv class for feasibility of strength reduction/induction
      variable elimination.  */
 
-  for (bl = ivs->loop_iv_list; bl; bl = bl->next)
+  for (bl = ivs->list; bl; bl = bl->next)
     {
       struct induction *v;
       int benefit;
-      int all_reduced;
-      rtx final_value = 0;
 
       /* Test whether it will be possible to eliminate this biv
-        provided all givs are reduced.  This is possible if either
-        the reg is not used outside the loop, or we can compute
-        what its final value will be.
-
-        For architectures with a decrement_and_branch_until_zero insn,
-        don't do this if we put a REG_NONNEG note on the endtest for
-        this biv.  */
-
-      /* Compare against bl->init_insn rather than loop_start.
-        We aren't concerned with any uses of the biv between
-        init_insn and loop_start since these won't be affected
-        by the value of the biv elsewhere in the function, so
-        long as init_insn doesn't use the biv itself.
-        March 14, 1989 -- self@bayes.arc.nasa.gov */
-
-      if ((REGNO_LAST_LUID (bl->regno) < INSN_LUID (loop_end)
-          && bl->init_insn
-          && INSN_UID (bl->init_insn) < max_uid_for_loop
-          && REGNO_FIRST_LUID (bl->regno) >= INSN_LUID (bl->init_insn)
-#ifdef HAVE_decrement_and_branch_until_zero
-          && ! bl->nonneg
-#endif
-          && ! reg_mentioned_p (bl->biv->dest_reg, SET_SRC (bl->init_set)))
-         || ((final_value = final_biv_value (loop, bl))
-#ifdef HAVE_decrement_and_branch_until_zero
-             && ! bl->nonneg
-#endif
-             ))
-       bl->eliminable = maybe_eliminate_biv (loop, bl, 0, threshold,
-                                             insn_count);
-      else
-       {
-         if (loop_dump_stream)
-           {
-             fprintf (loop_dump_stream,
-                      "Cannot eliminate biv %d.\n",
-                      bl->regno);
-             fprintf (loop_dump_stream,
-                      "First use: insn %d, last use: insn %d.\n",
-                      REGNO_FIRST_UID (bl->regno),
-                      REGNO_LAST_UID (bl->regno));
-           }
-       }
+        provided all givs are reduced.  */
+      bl->eliminable = loop_biv_eliminable_p (loop, bl, threshold, insn_count);
+
+      /* This will be true at the end, if all givs which depend on this
+        biv have been strength reduced.
+        We can't (currently) eliminate the biv unless this is so.  */
+      bl->all_reduced = 1;
 
-      /* Check each extension dependant giv in this class to see if its
+      /* Check each extension dependent giv in this class to see if its
         root biv is safe from wrapping in the interior mode.  */
-      check_ext_dependant_givs (bl, loop_info);
+      check_ext_dependent_givs (bl, loop_info);
 
       /* Combine all giv's for this iv_class.  */
       combine_givs (regs, bl);
 
-      /* This will be true at the end, if all givs which depend on this
-        biv have been strength reduced.
-        We can't (currently) eliminate the biv unless this is so.  */
-      all_reduced = 1;
-
-      /* Check each giv in this class to see if we will benefit by reducing
-        it.  Skip giv's combined with others.  */
       for (v = bl->giv; v; v = v->next_iv)
        {
          struct induction *tv;
-         int add_cost;
 
          if (v->ignore || v->same)
            continue;
 
-         benefit = v->benefit;
-         PUT_MODE (test_reg, v->mode);
-         add_cost = iv_add_mult_cost (bl->biv->add_val, v->mult_val,
-                                      test_reg, test_reg);
-
-         /* Reduce benefit if not replaceable, since we will insert
-            a move-insn to replace the insn that calculates this giv.
-            Don't do this unless the giv is a user variable, since it
-            will often be marked non-replaceable because of the duplication
-            of the exit code outside the loop.  In such a case, the copies
-            we insert are dead and will be deleted.  So they don't have
-            a cost.  Similar situations exist.  */
-         /* ??? The new final_[bg]iv_value code does a much better job
-            of finding replaceable giv's, and hence this code may no longer
-            be necessary.  */
-         if (! v->replaceable && ! bl->eliminable
-             && REG_USERVAR_P (v->dest_reg))
-           benefit -= copy_cost;
-
-         /* Decrease the benefit to count the add-insns that we will
-            insert to increment the reduced reg for the giv.
-            ??? This can overestimate the run-time cost of the additional
-            insns, e.g. if there are multiple basic blocks that increment
-            the biv, but only one of these blocks is executed during each
-            iteration.  There is no good way to detect cases like this with
-            the current structure of the loop optimizer.
-            This code is more accurate for determining code size than
-            run-time benefits.  */
-         benefit -= add_cost * bl->biv_count;
-
-         /* Decide whether to strength-reduce this giv or to leave the code
-            unchanged (recompute it from the biv each time it is used).
-            This decision can be made independently for each giv.  */
-
-#ifdef AUTO_INC_DEC
-         /* Attempt to guess whether autoincrement will handle some of the
-            new add insns; if so, increase BENEFIT (undo the subtraction of
-            add_cost that was done above).  */
-         if (v->giv_type == DEST_ADDR
-             /* Increasing the benefit is risky, since this is only a guess.
-                Avoid increasing register pressure in cases where there would
-                be no other benefit from reducing this giv.  */
-             && benefit > 0
-             && GET_CODE (v->mult_val) == CONST_INT)
-           {
-             if (HAVE_POST_INCREMENT
-                 && INTVAL (v->mult_val) == GET_MODE_SIZE (v->mem_mode))
-               benefit += add_cost * bl->biv_count;
-             else if (HAVE_PRE_INCREMENT
-                      && INTVAL (v->mult_val) == GET_MODE_SIZE (v->mem_mode))
-               benefit += add_cost * bl->biv_count;
-             else if (HAVE_POST_DECREMENT
-                      && -INTVAL (v->mult_val) == GET_MODE_SIZE (v->mem_mode))
-               benefit += add_cost * bl->biv_count;
-             else if (HAVE_PRE_DECREMENT
-                      && -INTVAL (v->mult_val) == GET_MODE_SIZE (v->mem_mode))
-               benefit += add_cost * bl->biv_count;
-           }
-#endif
+         benefit = loop_giv_reduce_benefit (loop, bl, v, test_reg);
 
          /* If an insn is not to be strength reduced, then set its ignore
-            flag, and clear all_reduced.  */
+            flag, and clear bl->all_reduced.  */
 
          /* A giv that depends on a reversed biv must be reduced if it is
             used after the loop exit, otherwise, it would have the wrong
@@ -3997,8 +5271,9 @@ strength_reduce (loop, insn_count, flags)
             of such giv's whether or not we know they are used after the loop
             exit.  */
 
-         if ( ! flag_reduce_all_givs && v->lifetime * threshold * benefit < insn_count
-             && ! bl->reversed )
+         if (! flag_reduce_all_givs
+             && v->lifetime * threshold * benefit < insn_count
+             && ! bl->reversed)
            {
              if (loop_dump_stream)
                fprintf (loop_dump_stream,
@@ -4006,7 +5281,7 @@ strength_reduce (loop, insn_count, flags)
                         INSN_UID (v->insn),
                         v->lifetime * threshold * benefit, insn_count);
              v->ignore = 1;
-             all_reduced = 0;
+             bl->all_reduced = 0;
            }
          else
            {
@@ -4022,7 +5297,7 @@ strength_reduce (loop, insn_count, flags)
                               "giv of insn %d: would need a multiply.\n",
                               INSN_UID (v->insn));
                    v->ignore = 1;
-                   all_reduced = 0;
+                   bl->all_reduced = 0;
                    break;
                  }
            }
@@ -4032,144 +5307,10 @@ strength_reduce (loop, insn_count, flags)
         last use is the definition of another giv.  If so, it is likely
         dead and should not be used to derive another giv nor to
         eliminate a biv.  */
-      for (v = bl->giv; v; v = v->next_iv)
-       {
-         if (v->ignore
-             || (v->same && v->same->ignore))
-           continue;
-
-         if (v->giv_type == DEST_REG
-             && REGNO_FIRST_UID (REGNO (v->dest_reg)) == INSN_UID (v->insn))
-           {
-             struct induction *v1;
-
-             for (v1 = bl->giv; v1; v1 = v1->next_iv)
-               if (REGNO_LAST_UID (REGNO (v->dest_reg)) == INSN_UID (v1->insn))
-                 v->maybe_dead = 1;
-           }
-       }
+      loop_givs_dead_check (loop, bl);
 
       /* Reduce each giv that we decided to reduce.  */
-
-      for (v = bl->giv; v; v = v->next_iv)
-       {
-         struct induction *tv;
-         if (! v->ignore && v->same == 0)
-           {
-             int auto_inc_opt = 0;
-
-             /* If the code for derived givs immediately below has already
-                allocated a new_reg, we must keep it.  */
-             if (! v->new_reg)
-               v->new_reg = gen_reg_rtx (v->mode);
-
-#ifdef AUTO_INC_DEC
-             /* If the target has auto-increment addressing modes, and
-                this is an address giv, then try to put the increment
-                immediately after its use, so that flow can create an
-                auto-increment addressing mode.  */
-             if (v->giv_type == DEST_ADDR && bl->biv_count == 1
-                 && bl->biv->always_executed && ! bl->biv->maybe_multiple
-                 /* We don't handle reversed biv's because bl->biv->insn
-                    does not have a valid INSN_LUID.  */
-                 && ! bl->reversed
-                 && v->always_executed && ! v->maybe_multiple
-                 && INSN_UID (v->insn) < max_uid_for_loop)
-               {
-                 /* If other giv's have been combined with this one, then
-                    this will work only if all uses of the other giv's occur
-                    before this giv's insn.  This is difficult to check.
-
-                    We simplify this by looking for the common case where
-                    there is one DEST_REG giv, and this giv's insn is the
-                    last use of the dest_reg of that DEST_REG giv.  If the
-                    increment occurs after the address giv, then we can
-                    perform the optimization.  (Otherwise, the increment
-                    would have to go before other_giv, and we would not be
-                    able to combine it with the address giv to get an
-                    auto-inc address.)  */
-                 if (v->combined_with)
-                   {
-                     struct induction *other_giv = 0;
-
-                     for (tv = bl->giv; tv; tv = tv->next_iv)
-                       if (tv->same == v)
-                         {
-                           if (other_giv)
-                             break;
-                           else
-                             other_giv = tv;
-                         }
-                     if (! tv && other_giv
-                         && REGNO (other_giv->dest_reg) < max_reg_before_loop
-                         && (REGNO_LAST_UID (REGNO (other_giv->dest_reg))
-                             == INSN_UID (v->insn))
-                         && INSN_LUID (v->insn) < INSN_LUID (bl->biv->insn))
-                       auto_inc_opt = 1;
-                   }
-                 /* Check for case where increment is before the address
-                    giv.  Do this test in "loop order".  */
-                 else if ((INSN_LUID (v->insn) > INSN_LUID (bl->biv->insn)
-                           && (INSN_LUID (v->insn) < INSN_LUID (loop->scan_start)
-                               || (INSN_LUID (bl->biv->insn)
-                                   > INSN_LUID (loop->scan_start))))
-                          || (INSN_LUID (v->insn) < INSN_LUID (loop->scan_start)
-                              && (INSN_LUID (loop->scan_start)
-                                  < INSN_LUID (bl->biv->insn))))
-                   auto_inc_opt = -1;
-                 else
-                   auto_inc_opt = 1;
-
-#ifdef HAVE_cc0
-                 {
-                   rtx prev;
-
-                   /* We can't put an insn immediately after one setting
-                      cc0, or immediately before one using cc0.  */
-                   if ((auto_inc_opt == 1 && sets_cc0_p (PATTERN (v->insn)))
-                       || (auto_inc_opt == -1
-                           && (prev = prev_nonnote_insn (v->insn)) != 0
-                           && INSN_P (prev)
-                           && sets_cc0_p (PATTERN (prev))))
-                     auto_inc_opt = 0;
-                 }
-#endif
-
-                 if (auto_inc_opt)
-                   v->auto_inc_opt = 1;
-               }
-#endif
-
-             /* For each place where the biv is incremented, add an insn
-                to increment the new, reduced reg for the giv.  */
-             for (tv = bl->biv; tv; tv = tv->next_iv)
-               {
-                 rtx insert_before;
-
-                 if (! auto_inc_opt)
-                   insert_before = tv->insn;
-                 else if (auto_inc_opt == 1)
-                   insert_before = NEXT_INSN (v->insn);
-                 else
-                   insert_before = v->insn;
-
-                 if (tv->mult_val == const1_rtx)
-                   emit_iv_add_mult (tv->add_val, v->mult_val,
-                                     v->new_reg, v->new_reg, insert_before);
-                 else /* tv->mult_val == const0_rtx */
-                   /* A multiply is acceptable here
-                      since this is presumed to be seldom executed.  */
-                   emit_iv_add_mult (tv->add_val, v->mult_val,
-                                     v->add_val, v->new_reg, insert_before);
-               }
-
-             /* Add code at loop start to initialize giv's reduced reg.  */
-
-             emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value),
-                               v->mult_val, v->add_val, v->new_reg,
-                               loop_start);
-           }
-       }
+      loop_givs_reduce (loop, bl);
 
       /* Rescan all givs.  If a giv is the same as a giv not reduced, mark it
         as not reduced.
@@ -4177,141 +5318,7 @@ strength_reduce (loop, insn_count, flags)
         For each giv register that can be reduced now: if replaceable,
         substitute reduced reg wherever the old giv occurs;
         else add new move insn "giv_reg = reduced_reg".  */
-
-      for (v = bl->giv; v; v = v->next_iv)
-       {
-         if (v->same && v->same->ignore)
-           v->ignore = 1;
-
-         if (v->ignore)
-           continue;
-
-         /* Update expression if this was combined, in case other giv was
-            replaced.  */
-         if (v->same)
-           v->new_reg = replace_rtx (v->new_reg,
-                                     v->same->dest_reg, v->same->new_reg);
-
-         /* See if this register is known to be a pointer to something.  If
-            so, see if we can find the alignment.  First see if there is a
-            destination register that is a pointer.  If so, this shares the
-            alignment too.  Next see if we can deduce anything from the
-            computational information.  If not, and this is a DEST_ADDR
-            giv, at least we know that it's a pointer, though we don't know
-            the alignment.  */
-         if (GET_CODE (v->new_reg) == REG
-             && v->giv_type == DEST_REG
-             && REG_POINTER (v->dest_reg))
-           mark_reg_pointer (v->new_reg,
-                             REGNO_POINTER_ALIGN (REGNO (v->dest_reg)));
-         else if (GET_CODE (v->new_reg) == REG
-                  && REG_POINTER (v->src_reg))
-           {
-             unsigned int align = REGNO_POINTER_ALIGN (REGNO (v->src_reg));
-
-             if (align == 0
-                 || GET_CODE (v->add_val) != CONST_INT
-                 || INTVAL (v->add_val) % (align / BITS_PER_UNIT) != 0)
-               align = 0;
-
-             mark_reg_pointer (v->new_reg, align);
-           }
-         else if (GET_CODE (v->new_reg) == REG
-                  && GET_CODE (v->add_val) == REG
-                  && REG_POINTER (v->add_val))
-           {
-             unsigned int align = REGNO_POINTER_ALIGN (REGNO (v->add_val));
-
-             if (align == 0 || GET_CODE (v->mult_val) != CONST_INT
-                 || INTVAL (v->mult_val) % (align / BITS_PER_UNIT) != 0)
-               align = 0;
-
-             mark_reg_pointer (v->new_reg, align);
-           }
-         else if (GET_CODE (v->new_reg) == REG && v->giv_type == DEST_ADDR)
-           mark_reg_pointer (v->new_reg, 0);
-
-         if (v->giv_type == DEST_ADDR)
-           /* Store reduced reg as the address in the memref where we found
-              this giv.  */
-           validate_change (v->insn, v->location, v->new_reg, 0);
-         else if (v->replaceable)
-           {
-             reg_map[REGNO (v->dest_reg)] = v->new_reg;
-
-#if 0
-             /* I can no longer duplicate the original problem.  Perhaps
-                this is unnecessary now?  */
-
-             /* Replaceable; it isn't strictly necessary to delete the old
-                insn and emit a new one, because v->dest_reg is now dead.
-
-                However, especially when unrolling loops, the special
-                handling for (set REG0 REG1) in the second cse pass may
-                make v->dest_reg live again.  To avoid this problem, emit
-                an insn to set the original giv reg from the reduced giv.
-                We can not delete the original insn, since it may be part
-                of a LIBCALL, and the code in flow that eliminates dead
-                libcalls will fail if it is deleted.  */
-             emit_insn_after (gen_move_insn (v->dest_reg, v->new_reg),
-                              v->insn);
-#endif
-           }
-         else
-           {
-             /* Not replaceable; emit an insn to set the original giv reg from
-                the reduced giv, same as above.  */
-             emit_insn_after (gen_move_insn (v->dest_reg, v->new_reg),
-                              v->insn);
-           }
-
-         /* When a loop is reversed, givs which depend on the reversed
-            biv, and which are live outside the loop, must be set to their
-            correct final value.  This insn is only needed if the giv is
-            not replaceable.  The correct final value is the same as the
-            value that the giv starts the reversed loop with.  */
-         if (bl->reversed && ! v->replaceable)
-           emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value),
-                             v->mult_val, v->add_val, v->dest_reg,
-                             end_insert_before);
-         else if (v->final_value)
-           {
-             rtx insert_before;
-
-             /* If the loop has multiple exits, emit the insn before the
-                loop to ensure that it will always be executed no matter
-                how the loop exits.  Otherwise, emit the insn after the loop,
-                since this is slightly more efficient.  */
-             if (loop->exit_count)
-               insert_before = loop_start;
-             else
-               insert_before = end_insert_before;
-             emit_insn_before (gen_move_insn (v->dest_reg, v->final_value),
-                               insert_before);
-
-#if 0
-             /* If the insn to set the final value of the giv was emitted
-                before the loop, then we must delete the insn inside the loop
-                that sets it.  If this is a LIBCALL, then we must delete
-                every insn in the libcall.  Note, however, that
-                final_giv_value will only succeed when there are multiple
-                exits if the giv is dead at each exit, hence it does not
-                matter that the original insn remains because it is dead
-                anyways.  */
-             /* Delete the insn inside the loop that sets the giv since
-                the giv is now set before (or after) the loop.  */
-             delete_insn (v->insn);
-#endif
-           }
-
-         if (loop_dump_stream)
-           {
-             fprintf (loop_dump_stream, "giv at %d reduced to ",
-                      INSN_UID (v->insn));
-             print_rtl (loop_dump_stream, v->new_reg);
-             fprintf (loop_dump_stream, "\n");
-           }
-       }
+      loop_givs_rescan (loop, bl, reg_map);
 
       /* All the givs based on the biv bl have been reduced if they
         merit it.  */
@@ -4321,23 +5328,23 @@ strength_reduce (loop, insn_count, flags)
         v->new_reg will either be or refer to the register of the giv it
         combined with.
 
-        Doing this clearing avoids problems in biv elimination where a
-        giv's new_reg is a complex value that can't be put in the insn but
-        the giv combined with (with a reg as new_reg) is marked maybe_dead.
-        Since the register will be used in either case, we'd prefer it be
-        used from the simpler giv.  */
+        Doing this clearing avoids problems in biv elimination where
+        a giv's new_reg is a complex value that can't be put in the
+        insn but the giv combined with (with a reg as new_reg) is
+        marked maybe_dead.  Since the register will be used in either
+        case, we'd prefer it be used from the simpler giv.  */
 
       for (v = bl->giv; v; v = v->next_iv)
        if (! v->maybe_dead && v->same)
          v->same->maybe_dead = 0;
 
       /* Try to eliminate the biv, if it is a candidate.
-        This won't work if ! all_reduced,
+        This won't work if ! bl->all_reduced,
         since the givs we planned to use might not have been reduced.
 
-        We have to be careful that we didn't initially think we could eliminate
-        this biv because of a giv that we now think may be dead and shouldn't
-        be used as a biv replacement.
+        We have to be careful that we didn't initially think we could
+        eliminate this biv because of a giv that we now think may be
+        dead and shouldn't be used as a biv replacement.
 
         Also, there is the possibility that we may have a giv that looks
         like it can be used to eliminate a biv, but the resulting insn
@@ -4349,7 +5356,7 @@ strength_reduce (loop, insn_count, flags)
         of the occurrences of the biv with a giv, but no harm was done in
         doing so in the rare cases where it can occur.  */
 
-      if (all_reduced == 1 && bl->eliminable
+      if (bl->all_reduced == 1 && bl->eliminable
          && maybe_eliminate_biv (loop, bl, 1, threshold, insn_count))
        {
          /* ?? If we created a new test to bypass the loop entirely,
@@ -4358,52 +5365,32 @@ strength_reduce (loop, insn_count, flags)
             pass has more hope of removing the initialization of this
             biv entirely.  */
 
-         /* If final_value != 0, then the biv may be used after loop end
-            and we must emit an insn to set it just in case.
-
-            Reversed bivs already have an insn after the loop setting their
-            value, so we don't need another one.  We can't calculate the
-            proper final value for such a biv here anyways.  */
-         if (final_value != 0 && ! bl->reversed)
-           {
-             rtx insert_before;
-
-             /* If the loop has multiple exits, emit the insn before the
-                loop to ensure that it will always be executed no matter
-                how the loop exits.  Otherwise, emit the insn after the
-                loop, since this is slightly more efficient.  */
-             if (loop->exit_count)
-               insert_before = loop_start;
-             else
-               insert_before = end_insert_before;
-
-             emit_insn_before (gen_move_insn (bl->biv->dest_reg, final_value),
-                               end_insert_before);
-           }
+         /* If final_value != 0, then the biv may be used after loop end
+            and we must emit an insn to set it just in case.
 
-#if 0
-         /* Delete all of the instructions inside the loop which set
-            the biv, as they are all dead.  If is safe to delete them,
-            because an insn setting a biv will never be part of a libcall.  */
-         /* However, deleting them will invalidate the regno_last_uid info,
-            so keeping them around is more convenient.  Final_biv_value
-            will only succeed when there are multiple exits if the biv
-            is dead at each exit, hence it does not matter that the original
-            insn remains, because it is dead anyways.  */
-         for (v = bl->biv; v; v = v->next_iv)
-           delete_insn (v->insn);
-#endif
+            Reversed bivs already have an insn after the loop setting their
+            value, so we don't need another one.  We can't calculate the
+            proper final value for such a biv here anyways.  */
+         if (bl->final_value && ! bl->reversed)
+             loop_insn_sink_or_swim (loop,
+                                     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",
                     bl->regno);
        }
+      /* See above note wrt final_value.  But since we couldn't eliminate
+        the biv, we must set the value after the loop instead of before.  */
+      else if (bl->final_value && ! bl->reversed)
+       loop_insn_sink (loop, gen_load_of_final_value (bl->biv->dest_reg,
+                                                      bl->final_value));
     }
 
   /* Go through all the instructions in the loop, making all the
      register substitutions scheduled in REG_MAP.  */
 
-  for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
+  for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
     if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
        || GET_CODE (p) == CALL_INSN)
       {
@@ -4444,45 +5431,32 @@ strength_reduce (loop, insn_count, flags)
      collected.  Always unroll loops that would be as small or smaller
      unrolled than when rolled.  */
   if ((flags & LOOP_UNROLL)
-      || (loop_info->n_iterations > 0
+      || ((flags & LOOP_AUTO_UNROLL)
+         && loop_info->n_iterations > 0
          && unrolled_insn_copies <= insn_count))
-    unroll_loop (loop, insn_count, end_insert_before, 1);
+    unroll_loop (loop, insn_count, 1);
 
 #ifdef HAVE_doloop_end
   if (HAVE_doloop_end && (flags & LOOP_BCT) && flag_branch_on_count_reg)
     doloop_optimize (loop);
 #endif  /* HAVE_doloop_end  */
 
+  /* In case number of iterations is known, drop branch prediction note
+     in the branch.  Do that only in second loop pass, as loop unrolling
+     may change the number of iterations performed.  */
+  if (flags & LOOP_BCT)
+    {
+      unsigned HOST_WIDE_INT n
+       = loop_info->n_iterations / loop_info->unroll_number;
+      if (n > 1)
+       predict_insn (prev_nonnote_insn (loop->end), PRED_LOOP_ITERATIONS,
+                     REG_BR_PROB_BASE - REG_BR_PROB_BASE / n);
+    }
+
   if (loop_dump_stream)
     fprintf (loop_dump_stream, "\n");
 
-egress:
-  VARRAY_FREE (ivs->reg_iv_type);
-  VARRAY_FREE (ivs->reg_iv_info);
-  free (ivs->reg_biv_class);
-  {
-    struct iv_class *iv = ivs->loop_iv_list;
-
-    while (iv) {
-      struct iv_class *next = iv->next;
-      struct induction *induction;
-      struct induction *next_induction;
-
-      for (induction = iv->biv; induction; induction = next_induction)
-       {
-         next_induction = induction->next_iv;
-         free (induction);
-       }
-      for (induction = iv->giv; induction; induction = next_induction)
-       {
-         next_induction = induction->next_iv;
-         free (induction);
-       }
-
-      free (iv);
-      iv = next;
-    }
-  }
+  loop_ivs_free (loop);
   if (reg_map)
     free (reg_map);
 }
@@ -4526,7 +5500,7 @@ check_insn_for_bivs (loop, p, not_every_iteration, maybe_multiple)
                          not_every_iteration, maybe_multiple);
              REG_IV_TYPE (ivs, REGNO (dest_reg)) = BASIC_INDUCT;
            }
-         else if (REGNO (dest_reg) < max_reg_before_loop)
+         else if (REGNO (dest_reg) < ivs->n_regs)
            REG_IV_TYPE (ivs, REGNO (dest_reg)) = NOT_BASIC_INDUCT;
        }
     }
@@ -4550,7 +5524,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
   if (GET_CODE (p) == INSN
       && (set = single_set (p))
       && GET_CODE (SET_DEST (set)) == REG
-      && ! VARRAY_CHAR (regs->may_not_optimize, REGNO (SET_DEST (set))))
+      && ! regs->array[REGNO (SET_DEST (set))].may_not_optimize)
     {
       rtx src_reg;
       rtx dest_reg;
@@ -4579,7 +5553,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
          /* Don't recognize a BASIC_INDUCT_VAR here.  */
          && dest_reg != src_reg
          /* This must be the only place where the register is set.  */
-         && (VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) == 1
+         && (regs->array[REGNO (dest_reg)].n_times_set == 1
              /* or all sets must be consecutive and make a giv.  */
              || (benefit = consec_sets_giv (loop, benefit, p,
                                             src_reg, dest_reg,
@@ -4594,24 +5568,20 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
            benefit += libcall_benefit (p);
 
          /* Skip the consecutive insns, if there are any.  */
-         if (VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) != 1)
+         if (regs->array[REGNO (dest_reg)].n_times_set != 1)
            p = last_consec_insn;
 
          record_giv (loop, v, p, src_reg, dest_reg, mult_val, add_val,
                      ext_val, benefit, DEST_REG, not_every_iteration,
-                     maybe_multiple, NULL_PTR);
+                     maybe_multiple, (rtx*) 0);
 
        }
     }
 
-#ifndef DONT_REDUCE_ADDR
   /* Look for givs which are memory addresses.  */
-  /* This resulted in worse code on a VAX 8600.  I wonder if it
-     still does.  */
   if (GET_CODE (p) == INSN)
     find_mem_givs (loop, PATTERN (p), p, not_every_iteration,
                   maybe_multiple);
-#endif
 
   /* Update the status of whether giv can derive other givs.  This can
      change when we pass a label or an insn that updates a biv.  */
@@ -4664,7 +5634,7 @@ valid_initial_value_p (x, insn, call_seen, loop_start)
    as a possible giv.  INSN is the insn whose pattern X comes from.
    NOT_EVERY_ITERATION is 1 if the insn might not be executed during
    every loop iteration.  MAYBE_MULTIPLE is 1 if the insn might be executed
-   more thanonce in each loop iteration.  */
+   more than once in each loop iteration.  */
 
 static void
 find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
@@ -4673,9 +5643,9 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
      rtx insn;
      int not_every_iteration, maybe_multiple;
 {
-  register int i, j;
-  register enum rtx_code code;
-  register const char *fmt;
+  int i, j;
+  enum rtx_code code;
+  const char *fmt;
 
   if (x == 0)
     return;
@@ -4708,7 +5678,7 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
        /* This code used to disable creating GIVs with mult_val == 1 and
           add_val == 0.  However, this leads to lost optimizations when
           it comes time to combine a set of related DEST_ADDR GIVs, since
-          this one would not be seen.   */
+          this one would not be seen.  */
 
        if (general_induction_var (loop, XEXP (x, 0), &src_reg, &add_val,
                                   &mult_val, &ext_val, 1, &benefit,
@@ -4722,7 +5692,7 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
                        add_val, ext_val, benefit, DEST_ADDR,
                        not_every_iteration, maybe_multiple, &XEXP (x, 0));
 
-           v->mem_mode = GET_MODE (x);
+           v->mem = x;
          }
       }
       return;
@@ -4781,17 +5751,18 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
   v->dest_reg = dest_reg;
   v->mult_val = mult_val;
   v->add_val = inc_val;
-  v->ext_dependant = NULL_RTX;
+  v->ext_dependent = NULL_RTX;
   v->location = location;
   v->mode = GET_MODE (dest_reg);
   v->always_computable = ! not_every_iteration;
   v->always_executed = ! not_every_iteration;
   v->maybe_multiple = maybe_multiple;
+  v->same = 0;
 
   /* Add this to the reg's iv_class, creating a class
      if this is the first incrementation of the reg.  */
 
-  bl = ivs->reg_biv_class[REGNO (dest_reg)];
+  bl = REG_IV_CLASS (ivs, REGNO (dest_reg));
   if (bl == 0)
     {
       /* Create and initialize new iv_class.  */
@@ -4806,6 +5777,7 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
 
       /* Set initial value to the reg itself.  */
       bl->initial_value = dest_reg;
+      bl->final_value = 0;
       /* We haven't seen the initializing insn yet */
       bl->init_insn = 0;
       bl->init_set = 0;
@@ -4816,12 +5788,23 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
       bl->reversed = 0;
       bl->total_benefit = 0;
 
-      /* Add this class to ivs->loop_iv_list.  */
-      bl->next = ivs->loop_iv_list;
-      ivs->loop_iv_list = bl;
+      /* Add this class to ivs->list.  */
+      bl->next = ivs->list;
+      ivs->list = bl;
 
       /* Put it in the array of biv register classes.  */
-      ivs->reg_biv_class[REGNO (dest_reg)] = bl;
+      REG_IV_CLASS (ivs, REGNO (dest_reg)) = bl;
+    }
+  else
+    {
+      /* Check if location is the same as a previous one.  */
+      struct induction *induction;
+      for (induction = bl->biv; induction; induction = induction->next_iv)
+       if (location == induction->location)
+         {
+           v->same = induction;
+           break;
+         }
     }
 
   /* Update IV_CLASS entry for this biv.  */
@@ -4832,23 +5815,7 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
     bl->incremented = 1;
 
   if (loop_dump_stream)
-    {
-      fprintf (loop_dump_stream,
-              "Insn %d: possible biv, reg %d,",
-              INSN_UID (insn), REGNO (dest_reg));
-      if (GET_CODE (inc_val) == CONST_INT)
-       {
-         fprintf (loop_dump_stream, " const =");
-         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (inc_val));
-         fputc ('\n', loop_dump_stream);
-       }
-      else
-       {
-         fprintf (loop_dump_stream, " const = ");
-         print_rtl (loop_dump_stream, inc_val);
-         fprintf (loop_dump_stream, "\n");
-       }
-    }
+    loop_biv_dump (v, loop_dump_stream, 0);
 }
 \f
 /* Fill in the data about one giv.
@@ -4884,9 +5851,12 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
   rtx set = single_set (insn);
   rtx temp;
 
-  /* Attempt to prove constantness of the values.  */
+  /* Attempt to prove constantness of the values.  Don't let simplify_rtx
+     undo the MULT canonicalization that we performed earlier.  */
   temp = simplify_rtx (add_val);
-  if (temp)
+  if (temp
+      && ! (GET_CODE (add_val) == MULT
+           && GET_CODE (temp) == ASHIFT))
     add_val = temp;
 
   v->insn = insn;
@@ -4895,7 +5865,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
   v->dest_reg = dest_reg;
   v->mult_val = mult_val;
   v->add_val = add_val;
-  v->ext_dependant = ext_val;
+  v->ext_dependent = ext_val;
   v->benefit = benefit;
   v->location = location;
   v->cant_derive = 0;
@@ -4936,8 +5906,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
     {
       v->mode = GET_MODE (SET_DEST (set));
 
-      v->lifetime = (REGNO_LAST_LUID (REGNO (dest_reg))
-                    - REGNO_FIRST_LUID (REGNO (dest_reg)));
+      v->lifetime = LOOP_REG_LIFETIME (loop, REGNO (dest_reg));
 
       /* If the lifetime is zero, it means that this register is
         really a dead store.  So mark this as a giv that can be
@@ -4951,7 +5920,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
 
   /* Add the giv to the class of givs computed from one biv.  */
 
-  bl = ivs->reg_biv_class[REGNO (src_reg)];
+  bl = REG_IV_CLASS (ivs, REGNO (src_reg));
   if (bl)
     {
       v->next_iv = bl->giv;
@@ -4967,17 +5936,20 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
     abort ();
 
   if (type == DEST_ADDR)
-    v->replaceable = 1;
+    {
+      v->replaceable = 1;
+      v->not_replaceable = 0;
+    }
   else
     {
       /* The giv can be replaced outright by the reduced register only if all
         of the following conditions are true:
-        - the insn that sets the giv is always executed on any iteration
+        - the insn that sets the giv is always executed on any iteration
           on which the giv is used at all
           (there are two ways to deduce this:
            either the insn is executed on every iteration,
            or all uses follow that insn in the same basic block),
-        - the giv is not used outside the loop
+        - the giv is not used outside the loop
         - no assignments to the biv occur during the giv's lifetime.  */
 
       if (REGNO_FIRST_UID (REGNO (dest_reg)) == INSN_UID (insn)
@@ -5002,6 +5974,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
             using this biv anyways.  */
 
          v->replaceable = 1;
+         v->not_replaceable = 0;
          for (b = bl->biv; b; b = b->next_iv)
            {
              if (INSN_UID (b->insn) >= max_uid_for_loop
@@ -5063,69 +6036,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
   }
 
   if (loop_dump_stream)
-    {
-      if (type == DEST_REG)
-       fprintf (loop_dump_stream, "Insn %d: giv reg %d",
-                INSN_UID (insn), REGNO (dest_reg));
-      else
-       fprintf (loop_dump_stream, "Insn %d: dest address",
-                INSN_UID (insn));
-
-      fprintf (loop_dump_stream, " src reg %d benefit %d",
-              REGNO (src_reg), v->benefit);
-      fprintf (loop_dump_stream, " lifetime %d",
-              v->lifetime);
-
-      if (v->replaceable)
-       fprintf (loop_dump_stream, " replaceable");
-
-      if (v->no_const_addval)
-       fprintf (loop_dump_stream, " ncav");
-
-      if (v->ext_dependant)
-       {
-         switch (GET_CODE (v->ext_dependant))
-           {
-           case SIGN_EXTEND:
-             fprintf (loop_dump_stream, " ext se");
-             break;
-           case ZERO_EXTEND:
-             fprintf (loop_dump_stream, " ext ze");
-             break;
-           case TRUNCATE:
-             fprintf (loop_dump_stream, " ext tr");
-             break;
-           default:
-             abort ();
-           }
-       }
-
-      if (GET_CODE (mult_val) == CONST_INT)
-       {
-         fprintf (loop_dump_stream, " mult ");
-         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (mult_val));
-       }
-      else
-       {
-         fprintf (loop_dump_stream, " mult ");
-         print_rtl (loop_dump_stream, mult_val);
-       }
-
-      if (GET_CODE (add_val) == CONST_INT)
-       {
-         fprintf (loop_dump_stream, " add ");
-         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (add_val));
-       }
-      else
-       {
-         fprintf (loop_dump_stream, " add ");
-         print_rtl (loop_dump_stream, add_val);
-       }
-    }
-
-  if (loop_dump_stream)
-    fprintf (loop_dump_stream, "\n");
-
+    loop_giv_dump (v, loop_dump_stream, 0);
 }
 
 /* All this does is determine whether a giv can be made replaceable because
@@ -5139,12 +6050,8 @@ check_final_value (loop, v)
      const struct loop *loop;
      struct induction *v;
 {
-  struct loop_ivs *ivs = LOOP_IVS (loop);
-  struct iv_class *bl;
   rtx final_value = 0;
 
-  bl = ivs->reg_biv_class[REGNO (v->src_reg)];
-
   /* DEST_ADDR givs will never reach here, because they are always marked
      replaceable above in record_giv.  */
 
@@ -5167,13 +6074,15 @@ check_final_value (loop, v)
 #endif
 
   if ((final_value = final_giv_value (loop, v))
-      && (v->always_computable || last_use_this_basic_block (v->dest_reg, v->insn)))
+      && (v->always_executed
+         || last_use_this_basic_block (v->dest_reg, v->insn)))
     {
       int biv_increment_seen = 0, before_giv_insn = 0;
       rtx p = v->insn;
       rtx last_giv_use;
 
       v->replaceable = 1;
+      v->not_replaceable = 0;
 
       /* When trying to determine whether or not a biv increment occurs
         during the lifetime of the giv, we can ignore uses of the variable
@@ -5324,7 +6233,7 @@ update_giv_derive (loop, p)
      subsequent biv update was performed.  If this adjustment cannot be done,
      the giv cannot derive further givs.  */
 
-  for (bl = ivs->loop_iv_list; bl; bl = bl->next)
+  for (bl = ivs->list; bl; bl = bl->next)
     for (biv = bl->biv; biv; biv = biv->next_iv)
       if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
          || biv->insn == p)
@@ -5422,7 +6331,7 @@ update_giv_derive (loop, p)
 static int
 basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
      const struct loop *loop;
-     register rtx x;
+     rtx x;
      enum machine_mode mode;
      rtx dest_reg;
      rtx p;
@@ -5430,7 +6339,7 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
      rtx *mult_val;
      rtx **location;
 {
-  register enum rtx_code code;
+  enum rtx_code code;
   rtx *argp, arg;
   rtx insn, set = 0;
 
@@ -5466,13 +6375,13 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
       return 1;
 
     case SUBREG:
-      /* If this is a SUBREG for a promoted variable, check the inner
-        value.  */
-      if (SUBREG_PROMOTED_VAR_P (x))
-       return basic_induction_var (loop, SUBREG_REG (x),
-                                   GET_MODE (SUBREG_REG (x)),
-                                   dest_reg, p, inc_val, mult_val, location);
-      return 0;
+      /* If what's inside the SUBREG is a BIV, then the SUBREG.  This will
+        handle addition of promoted variables.
+        ??? The comment at the start of this function is wrong: promoted
+        variable increments don't look like it says they do.  */
+      return basic_induction_var (loop, SUBREG_REG (x),
+                                 GET_MODE (SUBREG_REG (x)),
+                                 dest_reg, p, inc_val, mult_val, location);
 
     case REG:
       /* If this register is assigned in a previous insn, look at its
@@ -5523,7 +6432,7 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
       /* Fall through.  */
 
       /* Can accept constant setting of biv only when inside inner most loop.
-        Otherwise, a biv of an inner loop may be incorrectly recognized
+        Otherwise, a biv of an inner loop may be incorrectly recognized
         as a biv of the outer loop,
         causing code to be moved INTO the inner loop.  */
     case MEM:
@@ -5534,10 +6443,11 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
     case CONST:
       /* convert_modes aborts 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.  */
+        would be a useful iterator anyways.  convert_modes aborts if we try to
+        convert a float mode to non-float or vice versa too.  */
       if (loop->level == 1
-         && GET_MODE_CLASS (mode) != MODE_CC
-         && GET_MODE_CLASS (GET_MODE (dest_reg)) != MODE_CC)
+         && GET_MODE_CLASS (mode) == GET_MODE_CLASS (GET_MODE (dest_reg))
+         && GET_MODE_CLASS (mode) != MODE_CC)
        {
          /* Possible bug here?  Perhaps we don't know the mode of X.  */
          *inc_val = convert_modes (GET_MODE (dest_reg), mode, x, 0);
@@ -5548,6 +6458,9 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
        return 0;
 
     case SIGN_EXTEND:
+      /* Ignore this BIV if signed arithmetic overflow is defined.  */
+      if (flag_wrapv)
+       return 0;
       return basic_induction_var (loop, XEXP (x, 0), GET_MODE (XEXP (x, 0)),
                                  dest_reg, p, inc_val, mult_val, location);
 
@@ -5626,7 +6539,7 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
       /* Since this is now an invariant and wasn't before, it must be a giv
         with MULT_VAL == 0.  It doesn't matter which BIV we associate this
         with.  */
-      *src_reg = ivs->loop_iv_list->biv->dest_reg;
+      *src_reg = ivs->list->biv->dest_reg;
       *mult_val = const0_rtx;
       *add_val = x;
       break;
@@ -5685,7 +6598,7 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
 \f
 /* Given an expression, X, try to form it as a linear function of a biv.
    We will canonicalize it to be of the form
-       (plus (mult (BIV) (invar_1))
+       (plus (mult (BIV) (invar_1))
              (invar_2))
    with possible degeneracies.
 
@@ -5698,7 +6611,7 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
    expression that is neither invariant nor a biv or giv), this routine
    returns 0.
 
-   For a non-zero return, the result will have a code of CONST_INT, USE,
+   For a nonzero return, the result will have a code of CONST_INT, USE,
    REG (for a BIV), PLUS, or MULT.  No other codes will occur.
 
    *BENEFIT will be incremented by the benefit of any sub-giv encountered.  */
@@ -5751,7 +6664,7 @@ simplify_giv_expr (loop, x, ext_val, benefit)
          case CONST_INT:
          case USE:
            /* Adding two invariants must result in an invariant, so enclose
-              addition operation inside a USE and return it.  */
+              addition operation inside a USE and return it.  */
            if (GET_CODE (arg0) == USE)
              arg0 = XEXP (arg0, 0);
            if (GET_CODE (arg1) == USE)
@@ -5802,13 +6715,13 @@ simplify_giv_expr (loop, x, ext_val, benefit)
        tem = arg0, arg0 = arg1, arg1 = tem;
 
       if (GET_CODE (arg1) == PLUS)
-         return
-           simplify_giv_expr (loop,
-                              gen_rtx_PLUS (mode,
-                                            gen_rtx_PLUS (mode, arg0,
-                                                          XEXP (arg1, 0)),
-                                            XEXP (arg1, 1)),
-                              ext_val, benefit);
+       return
+         simplify_giv_expr (loop,
+                            gen_rtx_PLUS (mode,
+                                          gen_rtx_PLUS (mode, arg0,
+                                                        XEXP (arg1, 0)),
+                                          XEXP (arg1, 1)),
+                            ext_val, benefit);
 
       /* Now must have MULT + MULT.  Distribute if same biv, else not giv.  */
       if (GET_CODE (arg0) != MULT || GET_CODE (arg1) != MULT)
@@ -5885,7 +6798,7 @@ simplify_giv_expr (loop, x, ext_val, benefit)
                                                                    arg1)),
                                        ext_val, benefit);
            }
-         /* Porpagate the MULT expressions to the intermost nodes.  */
+         /* Propagate the MULT expressions to the intermost nodes.  */
          else if (GET_CODE (arg0) == PLUS)
            {
              /* (invar_0 + invar_1) * invar_2.  Distribute.  */
@@ -6002,7 +6915,7 @@ simplify_giv_expr (loop, x, ext_val, benefit)
               less harmful than reducing many givs that are not really
               beneficial.  */
            {
-             rtx single_use = VARRAY_RTX (regs->single_usage, REGNO (x));
+             rtx single_use = regs->array[REGNO (x)].single_usage;
              if (single_use && single_use != const0_rtx)
                *benefit += v->benefit;
            }
@@ -6019,12 +6932,12 @@ simplify_giv_expr (loop, x, ext_val, benefit)
            arg0 = simplify_giv_expr (loop, tem, ext_val, benefit);
            if (*ext_val)
              {
-               if (!v->ext_dependant)
+               if (!v->ext_dependent)
                  return arg0;
              }
            else
              {
-               *ext_val = v->ext_dependant;
+               *ext_val = v->ext_dependent;
                return arg0;
              }
            return 0;
@@ -6051,7 +6964,7 @@ simplify_giv_expr (loop, x, ext_val, benefit)
                      return simplify_giv_expr (loop, m->match->set_dest,
                                                ext_val, benefit);
 
-                   /* If consec is non-zero, this is a member of a group of
+                   /* If consec is nonzero, this is a member of a group of
                       instructions that were moved together.  We handle this
                       case only to the point of seeking to the last insn and
                       looking for a REG_EQUAL.  Fail if we don't find one.  */
@@ -6241,12 +7154,12 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
   v->benefit = first_benefit;
   v->cant_derive = 0;
   v->derive_adjustment = 0;
-  v->ext_dependant = NULL_RTX;
+  v->ext_dependent = NULL_RTX;
 
   REG_IV_TYPE (ivs, REGNO (dest_reg)) = GENERAL_INDUCT;
   REG_IV_INFO (ivs, REGNO (dest_reg)) = v;
 
-  count = VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) - 1;
+  count = regs->array[REGNO (dest_reg)].n_times_set - 1;
 
   while (count > 0)
     {
@@ -6305,7 +7218,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
    it cannot possibly be a valid address, 0 is returned.
 
    To perform the computation, we note that
-       G1 = x * v + a          and
+       G1 = x * v + a          and
        G2 = y * v + b
    where `v' is the biv.
 
@@ -6396,7 +7309,10 @@ express_from_1 (a, b, mult)
     }
   else if (CONSTANT_P (a))
     {
-      return simplify_gen_binary (MINUS, GET_MODE (b) != VOIDmode ? GET_MODE (b) : GET_MODE (a), const0_rtx, a);
+      enum machine_mode mode_a = GET_MODE (a);
+      enum machine_mode mode_b = GET_MODE (b);
+      enum machine_mode mode = mode_b == VOIDmode ? mode_a : mode_b;
+      return simplify_gen_binary (MINUS, mode, b, a);
     }
   else if (GET_CODE (b) == PLUS)
     {
@@ -6501,7 +7417,7 @@ combine_givs_p (g1, g2)
 {
   rtx comb, ret;
 
-  /* With the introduction of ext dependant givs, we must care for modes.
+  /* With the introduction of ext dependent givs, we must care for modes.
      G2 must not use a wider mode than G1.  */
   if (GET_MODE_SIZE (g1->mode) < GET_MODE_SIZE (g2->mode))
     return NULL_RTX;
@@ -6528,38 +7444,26 @@ combine_givs_p (g1, g2)
      the expression of G2 in terms of G1 can be used.  */
   if (ret != NULL_RTX
       && g2->giv_type == DEST_ADDR
-      && memory_address_p (g2->mem_mode, ret)
-      /* ??? Looses, especially with -fforce-addr, where *g2->location
-        will always be a register, and so anything more complicated
-        gets discarded.  */
-#if 0
-#ifdef ADDRESS_COST
-      && ADDRESS_COST (tem) <= ADDRESS_COST (*g2->location)
-#else
-      && rtx_cost (tem, MEM) <= rtx_cost (*g2->location, MEM)
-#endif
-#endif
-      )
-    {
-      return ret;
-    }
+      && memory_address_p (GET_MODE (g2->mem), ret))
+    return ret;
 
   return NULL_RTX;
 }
 \f
-/* Check each extension dependant giv in this class to see if its
+/* 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_dependant_givs (bl, loop_info)
+check_ext_dependent_givs (bl, loop_info)
      struct iv_class *bl;
      struct loop_info *loop_info;
 {
   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, u_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;
 
@@ -6567,7 +7471,7 @@ check_ext_dependant_givs (bl, loop_info)
      constants in order to be certain of no overflow.  */
   /* ??? An unknown iteration count with an increment of +-1
      combined with friendly exit tests of against an invariant
-     value is also ameanable to optimization.  Not implemented.  */
+     value is also amenable to optimization.  Not implemented.  */
   if (loop_info->n_iterations > 0
       && bl->initial_value
       && GET_CODE (bl->initial_value) == CONST_INT
@@ -6589,7 +7493,7 @@ check_ext_dependant_givs (bl, loop_info)
        neg_incr = 1, abs_incr = -abs_incr;
       total_incr = abs_incr * loop_info->n_iterations;
 
-      /* Check for host arithmatic overflow.  */
+      /* Check for host arithmetic overflow.  */
       if (total_incr / loop_info->n_iterations == abs_incr)
        {
          unsigned HOST_WIDE_INT u_max;
@@ -6602,7 +7506,7 @@ check_ext_dependant_givs (bl, loop_info)
 
          /* Check zero extension of biv ok.  */
          if (start_val >= 0
-             /* Check for host arithmatic overflow.  */
+             /* Check for host arithmetic overflow.  */
              && (neg_incr
                  ? u_end_val < u_start_val
                  : u_end_val > u_start_val)
@@ -6620,7 +7524,7 @@ check_ext_dependant_givs (bl, loop_info)
             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 arithmatic overflow.  */
+             /* Check for host arithmetic overflow.  */
              && (neg_incr
                  ? s_end_val < start_val
                  : s_end_val > start_val)
@@ -6636,9 +7540,9 @@ check_ext_dependant_givs (bl, loop_info)
 
   /* Invalidate givs that fail the tests.  */
   for (v = bl->giv; v; v = v->next_iv)
-    if (v->ext_dependant)
+    if (v->ext_dependent)
       {
-       enum rtx_code code = GET_CODE (v->ext_dependant);
+       enum rtx_code code = GET_CODE (v->ext_dependent);
        int ok = 0;
 
        switch (code)
@@ -6658,7 +7562,7 @@ check_ext_dependant_givs (bl, loop_info)
               derived GIV.  */
            if (se_ok && ze_ok)
              {
-               enum machine_mode outer_mode = GET_MODE (v->ext_dependant);
+               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,
@@ -6678,7 +7582,7 @@ check_ext_dependant_givs (bl, loop_info)
            if (loop_dump_stream)
              {
                fprintf (loop_dump_stream,
-                        "Verified ext dependant giv at %d of reg %d\n",
+                        "Verified ext dependent giv at %d of reg %d\n",
                         INSN_UID (v->insn), bl->regno);
              }
          }
@@ -6701,10 +7605,11 @@ check_ext_dependant_givs (bl, loop_info)
                  }
 
                fprintf (loop_dump_stream,
-                        "Failed ext dependant giv at %d, %s\n",
+                        "Failed ext dependent giv at %d, %s\n",
                         INSN_UID (v->insn), why);
              }
            v->ignore = 1;
+           bl->all_reduced = 0;
          }
       }
 }
@@ -6716,12 +7621,12 @@ extend_value_for_giv (v, value)
      struct induction *v;
      rtx value;
 {
-  rtx ext_dep = v->ext_dependant;
+  rtx ext_dep = v->ext_dependent;
 
   if (! ext_dep)
     return value;
 
-  /* Recall that check_ext_dependant_givs verified that the known bounds
+  /* Recall that check_ext_dependent_givs verified that the known bounds
      of a biv did not overflow or wrap with respect to the extension for
      the giv.  Therefore, constants need no additional adjustment.  */
   if (CONSTANT_P (value) && GET_MODE (value) == VOIDmode)
@@ -6804,8 +7709,7 @@ combine_givs (regs, bl)
         DEST_ADDR targets on hosts with reg+reg addressing, though it can
         be seen elsewhere as well.  */
       if (g1->giv_type == DEST_REG
-         && (single_use = VARRAY_RTX (regs->single_usage,
-                                      REGNO (g1->dest_reg)))
+         && (single_use = regs->array[REGNO (g1->dest_reg)].single_usage)
          && single_use != const0_rtx)
        continue;
 
@@ -6869,6 +7773,13 @@ restart:
 
              g2->new_reg = can_combine[i * giv_count + j];
              g2->same = g1;
+             /* For destination, we now may replace by mem expression instead
+                of register.  This changes the costs considerably, so add the
+                compensation.  */
+             if (g2->giv_type == DEST_ADDR)
+               g2->benefit = (g2->benefit + reg_address_cost
+                              - address_cost (g2->new_reg,
+                              GET_MODE (g2->mem)));
              g1->combined_with++;
              g1->lifetime += g2->lifetime;
 
@@ -6925,49 +7836,55 @@ restart:
   free (can_combine);
 }
 \f
-/* EMIT code before INSERT_BEFORE to set REG = B * M + A.  */
+/* Generate sequence for REG = B * M + A.  */
 
-void
-emit_iv_add_mult (b, m, a, reg, insert_before)
+static rtx
+gen_add_mult (b, m, a, reg)
      rtx b;          /* initial value of basic induction variable */
      rtx m;          /* multiplicative constant */
      rtx a;          /* additive constant */
      rtx reg;        /* destination register */
-     rtx insert_before;
 {
   rtx seq;
   rtx result;
 
-  /* Prevent unexpected sharing of these rtx.  */
-  a = copy_rtx (a);
-  b = copy_rtx (b);
-
-  /* Increase the lifetime of any invariants moved further in code.  */
-  update_reg_last_use (a, insert_before);
-  update_reg_last_use (b, insert_before);
-  update_reg_last_use (m, insert_before);
-
   start_sequence ();
+  /* Use unsigned arithmetic.  */
   result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 1);
   if (reg != result)
     emit_move_insn (reg, result);
-  seq = gen_sequence ();
+  seq = get_insns ();
   end_sequence ();
 
-  emit_insn_before (seq, insert_before);
+  return seq;
+}
+
+
+/* Update registers created in insn sequence SEQ.  */
 
-  /* It is entirely possible that the expansion created lots of new
-     registers.  Iterate over the sequence we just created and
-     record them all.  */
+static void
+loop_regs_update (loop, seq)
+     const struct loop *loop ATTRIBUTE_UNUSED;
+     rtx seq;
+{
+  rtx insn;
+
+  /* Update register info for alias analysis.  */
 
-  if (GET_CODE (seq) == SEQUENCE)
+  if (seq == NULL_RTX)
+    return;
+
+  if (INSN_P (seq))
     {
-      int i;
-      for (i = 0; i < XVECLEN (seq, 0); ++i)
+      insn = seq;
+      while (insn != NULL_RTX)
        {
-         rtx set = single_set (XVECEXP (seq, 0, i));
+         rtx set = single_set (insn);
+
          if (set && GET_CODE (SET_DEST (set)) == REG)
            record_base_value (REGNO (SET_DEST (set)), SET_SRC (set), 0);
+
+         insn = NEXT_INSN (insn);
        }
     }
   else if (GET_CODE (seq) == SET
@@ -6975,8 +7892,99 @@ emit_iv_add_mult (b, m, a, reg, insert_before)
     record_base_value (REGNO (SET_DEST (seq)), SET_SRC (seq), 0);
 }
 
-/* Similar to emit_iv_add_mult, but compute cost rather than emitting
-   insns.  */
+
+/* EMIT code before BEFORE_BB/BEFORE_INSN to set REG = B * M + A.  */
+
+void
+loop_iv_add_mult_emit_before (loop, b, m, a, reg, before_bb, before_insn)
+     const struct loop *loop;
+     rtx b;          /* initial value of basic induction variable */
+     rtx m;          /* multiplicative constant */
+     rtx a;          /* additive constant */
+     rtx reg;        /* destination register */
+     basic_block before_bb;
+     rtx before_insn;
+{
+  rtx seq;
+
+  if (! before_insn)
+    {
+      loop_iv_add_mult_hoist (loop, b, m, a, reg);
+      return;
+    }
+
+  /* Use copy_rtx to prevent unexpected sharing of these rtx.  */
+  seq = gen_add_mult (copy_rtx (b), copy_rtx (m), copy_rtx (a), reg);
+
+  /* Increase the lifetime of any invariants moved further in code.  */
+  update_reg_last_use (a, before_insn);
+  update_reg_last_use (b, before_insn);
+  update_reg_last_use (m, before_insn);
+
+  loop_insn_emit_before (loop, before_bb, before_insn, seq);
+
+  /* It is possible that the expansion created lots of new registers.
+     Iterate over the sequence we just created and record them all.  */
+  loop_regs_update (loop, seq);
+}
+
+
+/* Emit insns in loop pre-header to set REG = B * M + A.  */
+
+void
+loop_iv_add_mult_sink (loop, b, m, a, reg)
+     const struct loop *loop;
+     rtx b;          /* initial value of basic induction variable */
+     rtx m;          /* multiplicative constant */
+     rtx a;          /* additive constant */
+     rtx reg;        /* destination register */
+{
+  rtx seq;
+
+  /* Use copy_rtx to prevent unexpected sharing of these rtx.  */
+  seq = gen_add_mult (copy_rtx (b), copy_rtx (m), copy_rtx (a), reg);
+
+  /* Increase the lifetime of any invariants moved further in code.
+     ???? Is this really necessary?  */
+  update_reg_last_use (a, loop->sink);
+  update_reg_last_use (b, loop->sink);
+  update_reg_last_use (m, loop->sink);
+
+  loop_insn_sink (loop, seq);
+
+  /* It is possible that the expansion created lots of new registers.
+     Iterate over the sequence we just created and record them all.  */
+  loop_regs_update (loop, seq);
+}
+
+
+/* Emit insns after loop to set REG = B * M + A.  */
+
+void
+loop_iv_add_mult_hoist (loop, b, m, a, reg)
+     const struct loop *loop;
+     rtx b;          /* initial value of basic induction variable */
+     rtx m;          /* multiplicative constant */
+     rtx a;          /* additive constant */
+     rtx reg;        /* destination register */
+{
+  rtx seq;
+
+  /* Use copy_rtx to prevent unexpected sharing of these rtx.  */
+  seq = gen_add_mult (copy_rtx (b), copy_rtx (m), copy_rtx (a), reg);
+
+  loop_insn_hoist (loop, seq);
+
+  /* It is possible that the expansion created lots of new registers.
+     Iterate over the sequence we just created and record them all.  */
+  loop_regs_update (loop, seq);
+}
+
+
+
+/* Similar to gen_add_mult, but compute cost rather than generating
+   sequence.  */
+
 static int
 iv_add_mult_cost (b, m, a, reg)
      rtx b;          /* initial value of basic induction variable */
@@ -6988,7 +7996,7 @@ iv_add_mult_cost (b, m, a, reg)
   rtx last, result;
 
   start_sequence ();
-  result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 0);
+  result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 1);
   if (reg != result)
     emit_move_insn (reg, result);
   last = get_last_insn ();
@@ -7004,16 +8012,20 @@ iv_add_mult_cost (b, m, a, reg)
 }
 \f
 /* Test whether A * B can be computed without
-   an actual multiply insn.  Value is 1 if so.  */
+   an actual multiply insn.  Value is 1 if so.
+
+  ??? This function stinks because it generates a ton of wasted RTL
+  ??? and as a result fragments GC memory to no end.  There are other
+  ??? places in the compiler which are invoked a lot and do the same
+  ??? thing, generate wasted RTL just to see if something is possible.  */
 
 static int
 product_cheap_p (a, b)
      rtx a;
      rtx b;
 {
-  int i;
   rtx tmp;
-  int win = 1;
+  int win, n_insns;
 
   /* If only one is constant, make it B.  */
   if (GET_CODE (a) == CONST_INT)
@@ -7033,31 +8045,31 @@ product_cheap_p (a, b)
 
   start_sequence ();
   expand_mult (GET_MODE (a), a, b, NULL_RTX, 1);
-  tmp = gen_sequence ();
+  tmp = get_insns ();
   end_sequence ();
 
-  if (GET_CODE (tmp) == SEQUENCE)
+  win = 1;
+  if (INSN_P (tmp))
     {
-      if (XVEC (tmp, 0) == 0)
-       win = 1;
-      else if (XVECLEN (tmp, 0) > 3)
-       win = 0;
-      else
-       for (i = 0; i < XVECLEN (tmp, 0); i++)
-         {
-           rtx insn = XVECEXP (tmp, 0, i);
-
-           if (GET_CODE (insn) != INSN
-               || (GET_CODE (PATTERN (insn)) == SET
-                   && GET_CODE (SET_SRC (PATTERN (insn))) == MULT)
-               || (GET_CODE (PATTERN (insn)) == PARALLEL
-                   && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
-                   && GET_CODE (SET_SRC (XVECEXP (PATTERN (insn), 0, 0))) == MULT))
-             {
-               win = 0;
-               break;
-             }
-         }
+      n_insns = 0;
+      while (tmp != NULL_RTX)
+       {
+         rtx next = NEXT_INSN (tmp);
+
+         if (++n_insns > 3
+             || GET_CODE (tmp) != INSN
+             || (GET_CODE (PATTERN (tmp)) == SET
+                 && GET_CODE (SET_SRC (PATTERN (tmp))) == MULT)
+             || (GET_CODE (PATTERN (tmp)) == PARALLEL
+                 && GET_CODE (XVECEXP (PATTERN (tmp), 0, 0)) == SET
+                 && GET_CODE (SET_SRC (XVECEXP (PATTERN (tmp), 0, 0))) == MULT))
+           {
+             win = 0;
+             break;
+           }
+
+         tmp = next;
+       }
     }
   else if (GET_CODE (tmp) == SET
           && GET_CODE (SET_SRC (tmp)) == MULT)
@@ -7147,7 +8159,7 @@ check_dbra_loop (loop, insn_count)
      it will be zero on the last iteration.  Also skip if the biv is
      used between its update and the test insn.  */
 
-  for (bl = ivs->loop_iv_list; bl; bl = bl->next)
+  for (bl = ivs->list; bl; bl = bl->next)
     {
       if (bl->biv_count == 1
          && ! bl->biv->maybe_multiple
@@ -7239,9 +8251,12 @@ check_dbra_loop (loop, insn_count)
         which is reversible.  */
       int reversible_mem_store = 1;
 
-      if (bl->giv_count == 0 && ! loop->exit_count)
+      if (bl->giv_count == 0
+         && !loop->exit_count
+         && !loop_info->has_multiple_exit_targets)
        {
          rtx bivreg = regno_reg_rtx[bl->regno];
+         struct iv_class *blt;
 
          /* If there are no givs for this biv, and the only exit is the
             fall through at the end of the loop, then
@@ -7256,9 +8271,11 @@ check_dbra_loop (loop, insn_count)
                    && REGNO (SET_DEST (set)) == bl->regno)
                  /* An insn that sets the biv is okay.  */
                  ;
-               else if ((p == prev_nonnote_insn (prev_nonnote_insn (loop_end))
-                         || p == prev_nonnote_insn (loop_end))
-                        && reg_mentioned_p (bivreg, PATTERN (p)))
+               else if (!reg_mentioned_p (bivreg, PATTERN (p)))
+                 /* An insn that doesn't mention the biv is okay.  */
+                 ;
+               else if (p == prev_nonnote_insn (prev_nonnote_insn (loop_end))
+                        || p == prev_nonnote_insn (loop_end))
                  {
                    /* If either of these insns uses the biv and sets a pseudo
                       that has more than one usage, then the biv has uses
@@ -7272,12 +8289,22 @@ check_dbra_loop (loop, insn_count)
                        break;
                      }
                  }
-               else if (reg_mentioned_p (bivreg, PATTERN (p)))
+               else
                  {
                    no_use_except_counting = 0;
                    break;
                  }
              }
+
+         /* A biv has uses besides counting if it is used to set
+            another biv.  */
+         for (blt = ivs->list; blt; blt = blt->next)
+           if (blt->init_set
+               && reg_mentioned_p (bivreg, SET_SRC (blt->init_set)))
+             {
+               no_use_except_counting = 0;
+               break;
+             }
        }
 
       if (no_use_except_counting)
@@ -7299,12 +8326,11 @@ check_dbra_loop (loop, insn_count)
            {
              struct induction *v;
 
-             reversible_mem_store
-               = (! loop_info->unknown_address_altered
-                  && ! loop_info->unknown_constant_address_altered
-                  && ! loop_invariant_p (loop,
-                                         XEXP (XEXP (loop_info->store_mems, 0),
-                                               0)));
+             /* If we could prove that each of the memory locations
+                written to was different, then we could reverse the
+                store -- but we don't presently have any way of
+                knowing that.  */
+             reversible_mem_store = 0;
 
              /* If the store depends on a register that is set after the
                 store, it depends on the initial value, and is thus not
@@ -7332,13 +8358,14 @@ check_dbra_loop (loop, insn_count)
         about all these things.  */
 
       if ((num_nonfixed_reads <= 1
-          && ! loop_info->has_call
+          && ! loop_info->has_nonconst_call
+          && ! loop_info->has_prefetch
           && ! loop_info->has_volatile
           && reversible_mem_store
           && (bl->giv_count + bl->biv_count + loop_info->num_mem_sets
-              + LOOP_MOVABLES (loop)->num + compare_and_branch == insn_count)
-          && (bl == ivs->loop_iv_list && bl->next == 0))
-         || no_use_except_counting)
+              + num_unmoved_movables (loop) + compare_and_branch == insn_count)
+          && (bl == ivs->list && bl->next == 0))
+         || (no_use_except_counting && ! loop_info->has_prefetch))
        {
          rtx tem;
 
@@ -7484,9 +8511,7 @@ check_dbra_loop (loop, insn_count)
 
              /* Save some info needed to produce the new insns.  */
              reg = bl->biv->dest_reg;
-             jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 1);
-             if (jump_label == pc_rtx)
-               jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 2);
+             jump_label = condjump_label (PREV_INSN (loop_end));
              new_add_val = GEN_INT (-INTVAL (bl->biv->add_val));
 
              /* Set start_value; if this is not a CONST_INT, we need
@@ -7498,27 +8523,20 @@ check_dbra_loop (loop, insn_count)
                  && GET_CODE (comparison_value) == CONST_INT)
                {
                  start_value = GEN_INT (comparison_val - add_adjust);
-                 emit_insn_before (gen_move_insn (reg, start_value),
-                                   loop_start);
+                 loop_insn_hoist (loop, gen_move_insn (reg, start_value));
                }
              else if (GET_CODE (initial_value) == CONST_INT)
                {
-                 rtx offset = GEN_INT (-INTVAL (initial_value) - add_adjust);
                  enum machine_mode mode = GET_MODE (reg);
-                 enum insn_code icode
-                   = add_optab->handlers[(int) mode].insn_code;
-
-                 if (! (*insn_data[icode].operand[0].predicate) (reg, mode)
-                     || ! ((*insn_data[icode].operand[1].predicate)
-                           (comparison_value, mode))
-                     || ! ((*insn_data[icode].operand[2].predicate)
-                           (offset, mode)))
+                 rtx offset = GEN_INT (-INTVAL (initial_value) - add_adjust);
+                 rtx add_insn = gen_add3_insn (reg, comparison_value, offset);
+
+                 if (add_insn == 0)
                    return 0;
+
                  start_value
                    = gen_rtx_PLUS (mode, comparison_value, offset);
-                 emit_insn_before ((GEN_FCN (icode)
-                                    (reg, comparison_value, offset)),
-                                   loop_start);
+                 loop_insn_hoist (loop, add_insn);
                  if (GET_CODE (comparison) == LE)
                    final_value = gen_rtx_PLUS (mode, comparison_value,
                                                GEN_INT (add_val));
@@ -7526,19 +8544,14 @@ check_dbra_loop (loop, insn_count)
              else if (! add_adjust)
                {
                  enum machine_mode mode = GET_MODE (reg);
-                 enum insn_code icode
-                   = sub_optab->handlers[(int) mode].insn_code;
-                 if (! (*insn_data[icode].operand[0].predicate) (reg, mode)
-                     || ! ((*insn_data[icode].operand[1].predicate)
-                           (comparison_value, mode))
-                     || ! ((*insn_data[icode].operand[2].predicate)
-                           (initial_value, mode)))
+                 rtx sub_insn = gen_sub3_insn (reg, comparison_value,
+                                               initial_value);
+
+                 if (sub_insn == 0)
                    return 0;
                  start_value
                    = gen_rtx_MINUS (mode, comparison_value, initial_value);
-                 emit_insn_before ((GEN_FCN (icode)
-                                    (reg, comparison_value, initial_value)),
-                                   loop_start);
+                 loop_insn_hoist (loop, sub_insn);
                }
              else
                /* We could handle the other cases too, but it'll be
@@ -7549,10 +8562,10 @@ check_dbra_loop (loop, insn_count)
                 create a sequence to hold all the insns from expand_inc.  */
              start_sequence ();
              expand_inc (reg, new_add_val);
-             tem = gen_sequence ();
+             tem = get_insns ();
              end_sequence ();
 
-             p = emit_insn_before (tem, bl->biv->insn);
+             p = loop_insn_emit_before (loop, 0, bl->biv->insn, tem);
              delete_insn (bl->biv->insn);
 
              /* Update biv info to reflect its new status.  */
@@ -7578,20 +8591,19 @@ check_dbra_loop (loop, insn_count)
              if ((REGNO_LAST_UID (bl->regno) != INSN_UID (first_compare))
                  || ! bl->init_insn
                  || REGNO_FIRST_UID (bl->regno) != INSN_UID (bl->init_insn))
-               emit_insn_after (gen_move_insn (reg, final_value),
-                                loop_end);
+               loop_insn_sink (loop, gen_load_of_final_value (reg, final_value));
 
              /* Delete compare/branch at end of loop.  */
-             delete_insn (PREV_INSN (loop_end));
+             delete_related_insns (PREV_INSN (loop_end));
              if (compare_and_branch == 2)
-               delete_insn (first_compare);
+               delete_related_insns (first_compare);
 
              /* Add new compare/branch insn at end of loop.  */
              start_sequence ();
              emit_cmp_and_jump_insns (reg, const0_rtx, cmp_code, NULL_RTX,
-                                      GET_MODE (reg), 0, 0,
+                                      GET_MODE (reg), 0,
                                       XEXP (jump_label, 0));
-             tem = gen_sequence ();
+             tem = get_insns ();
              end_sequence ();
              emit_jump_insn_before (tem, loop_end);
 
@@ -7636,7 +8648,7 @@ check_dbra_loop (loop, insn_count)
                       REG_EQUAL notes should still be correct.  */
                    if (! set
                        || GET_CODE (SET_DEST (set)) != REG
-                       || (size_t) REGNO (SET_DEST (set)) >= ivs->reg_iv_type->num_elements
+                       || (size_t) REGNO (SET_DEST (set)) >= ivs->n_regs
                        || REG_IV_TYPE (ivs, REGNO (SET_DEST (set))) != GENERAL_INDUCT
                        || REG_IV_INFO (ivs, REGNO (SET_DEST (set)))->src_reg != bl->biv->src_reg)
                      for (pnote = &REG_NOTES (p); *pnote;)
@@ -7676,7 +8688,7 @@ check_dbra_loop (loop, insn_count)
 /* Verify whether the biv BL appears to be eliminable,
    based on the insns in the loop that refer to it.
 
-   If ELIMINATE_P is non-zero, actually do the elimination.
+   If ELIMINATE_P is nonzero, actually do the elimination.
 
    THRESHOLD and INSN_COUNT are from loop_optimize and are used to
    determine whether invariant insns should be placed inside or at the
@@ -7691,22 +8703,22 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   rtx reg = bl->biv->dest_reg;
-  rtx loop_start = loop->start;
-  rtx loop_end = loop->end;
   rtx p;
 
   /* Scan all insns in the loop, stopping if we find one that uses the
      biv in a way that we cannot eliminate.  */
 
-  for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
+  for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
     {
       enum rtx_code code = GET_CODE (p);
-      rtx where = threshold >= insn_count ? loop_start : p;
+      basic_block where_bb = 0;
+      rtx where_insn = threshold >= insn_count ? 0 : p;
+      rtx note;
 
       /* If this is a libcall that sets a giv, skip ahead to its end.  */
       if (GET_RTX_CLASS (code) == 'i')
        {
-         rtx note = find_reg_note (p, REG_LIBCALL, NULL_RTX);
+         note = find_reg_note (p, REG_LIBCALL, NULL_RTX);
 
          if (note)
            {
@@ -7717,17 +8729,19 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
                {
                  unsigned int regno = REGNO (SET_DEST (set));
 
-                 if (regno < max_reg_before_loop
+                 if (regno < ivs->n_regs
                      && REG_IV_TYPE (ivs, regno) == GENERAL_INDUCT
                      && REG_IV_INFO (ivs, regno)->src_reg == bl->biv->src_reg)
                    p = last;
                }
            }
        }
+
+      /* Closely examine the insn if the biv is mentioned.  */
       if ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
          && reg_mentioned_p (reg, PATTERN (p))
          && ! maybe_eliminate_biv_1 (loop, PATTERN (p), p, bl,
-                                     eliminate_p, where))
+                                     eliminate_p, where_bb, where_insn))
        {
          if (loop_dump_stream)
            fprintf (loop_dump_stream,
@@ -7735,9 +8749,15 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
                     bl->regno, INSN_UID (p));
          break;
        }
+
+      /* If we are eliminating, kill REG_EQUAL notes mentioning the biv.  */
+      if (eliminate_p
+         && (note = find_reg_note (p, REG_EQUAL, NULL_RTX)) != NULL_RTX
+         && reg_mentioned_p (reg, XEXP (note, 0)))
+       remove_note (p, note);
     }
 
-  if (p == loop_end)
+  if (p == loop->end)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream, "biv %d %s eliminated.\n",
@@ -7749,7 +8769,7 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
 }
 \f
 /* INSN and REFERENCE are instructions in the same insn chain.
-   Return non-zero if INSN is first.  */
+   Return nonzero if INSN is first.  */
 
 int
 loop_insn_first_p (insn, reference)
@@ -7762,9 +8782,9 @@ loop_insn_first_p (insn, reference)
       /* Start with test for not first so that INSN == REFERENCE yields not
          first.  */
       if (q == insn || ! p)
-        return 0;
+       return 0;
       if (p == reference || ! q)
-        return 1;
+       return 1;
 
       /* Either of P or Q might be a NOTE.  Notes have the same LUID as the
          previous insn, hence the <= comparison below does not work if
@@ -7782,7 +8802,7 @@ loop_insn_first_p (insn, reference)
     }
 }
 
-/* We are trying to eliminate BIV in INSN using GIV.  Return non-zero if
+/* We are trying to eliminate BIV in INSN using GIV.  Return nonzero if
    the offset that we have to take into account due to auto-increment /
    div derivation is zero.  */
 static int
@@ -7809,18 +8829,20 @@ biv_elimination_giv_has_0_offset (biv, giv, insn)
 
    If BIV does not appear in X, return 1.
 
-   If ELIMINATE_P is non-zero, actually do the elimination.  WHERE indicates
-   where extra insns should be added.  Depending on how many items have been
-   moved out of the loop, it will either be before INSN or at the start of
-   the loop.  */
+   If ELIMINATE_P is nonzero, actually do the elimination.
+   WHERE_INSN/WHERE_BB indicate where extra insns should be added.
+   Depending on how many items have been moved out of the loop, it
+   will either be before INSN (when WHERE_INSN is nonzero) or at the
+   start of the loop (when WHERE_INSN is zero).  */
 
 static int
-maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
+maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn)
      const struct loop *loop;
      rtx x, insn;
      struct iv_class *bl;
      int eliminate_p;
-     rtx where;
+     basic_block where_bb;
+     rtx where_insn;
 {
   enum rtx_code code = GET_CODE (x);
   rtx reg = bl->biv->dest_reg;
@@ -7930,8 +8952,9 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                   into a register (it will be a loop invariant.)  */
                tem = gen_reg_rtx (GET_MODE (v->new_reg));
 
-               emit_insn_before (gen_move_insn (tem, copy_rtx (v->add_val)),
-                                 where);
+               loop_insn_emit_before (loop, 0, where_insn,
+                                      gen_move_insn (tem,
+                                                     copy_rtx (v->add_val)));
 
                /* Substitute the new register for its invariant value in
                   the compare expression.  */
@@ -7975,6 +8998,22 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                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;
 
@@ -7985,21 +9024,22 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                   the derived constant can be directly placed in the COMPARE,
                   do so.  */
                if (GET_CODE (arg) == CONST_INT
-                   && GET_CODE (v->mult_val) == CONST_INT
                    && GET_CODE (v->add_val) == CONST_INT)
                  {
-                   validate_change (insn, &XEXP (x, arg_operand),
-                                    GEN_INT (INTVAL (arg)
-                                             * INTVAL (v->mult_val)
-                                             + INTVAL (v->add_val)), 1);
+                   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);
-                   emit_iv_add_mult (arg, v->mult_val, v->add_val, tem, where);
-                   validate_change (insn, &XEXP (x, arg_operand), tem, 1);
+                   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;
              }
@@ -8030,7 +9070,9 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                                 v->new_reg, 1);
 
                /* Compute value to compare against.  */
-               emit_iv_add_mult (arg, v->mult_val, v->add_val, tem, where);
+               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 ())
@@ -8066,8 +9108,9 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                                     v->new_reg, 1);
 
                    /* Compute value to compare against.  */
-                   emit_iv_add_mult (arg, v->mult_val, v->add_val,
-                                     tem, where);
+                   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;
@@ -8101,7 +9144,8 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
              if (v->ignore || v->maybe_dead || v->mode != mode)
                continue;
 
-             for (tv = ivs->reg_biv_class[REGNO (arg)]->giv; tv; tv = tv->next_iv)
+             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)
@@ -8147,14 +9191,14 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
        {
        case 'e':
          if (! maybe_eliminate_biv_1 (loop, XEXP (x, i), insn, bl,
-                                      eliminate_p, where))
+                                      eliminate_p, where_bb, where_insn))
            return 0;
          break;
 
        case 'E':
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            if (! maybe_eliminate_biv_1 (loop, XVECEXP (x, i, j), insn, bl,
-                                        eliminate_p, where))
+                                        eliminate_p, where_bb, where_insn))
              return 0;
          break;
        }
@@ -8195,11 +9239,11 @@ record_initial (dest, set, data)
   struct iv_class *bl;
 
   if (GET_CODE (dest) != REG
-      || REGNO (dest) >= max_reg_before_loop
+      || REGNO (dest) >= ivs->n_regs
       || REG_IV_TYPE (ivs, REGNO (dest)) != BASIC_INDUCT)
     return;
 
-  bl = ivs->reg_biv_class[REGNO (dest)];
+  bl = REG_IV_CLASS (ivs, REGNO (dest));
 
   /* If this is the first set found, record it.  */
   if (bl->init_insn == 0)
@@ -8212,7 +9256,7 @@ record_initial (dest, set, data)
 /* If any of the registers in X are "old" and currently have a last use earlier
    than INSN, update them to have a last use of INSN.  Their actual last use
    will be the previous insn but it will not have a valid uid_luid so we can't
-   use it.  */
+   use it.  X must be a source expression only.  */
 
 static void
 update_reg_last_use (x, insn)
@@ -8222,15 +9266,19 @@ update_reg_last_use (x, insn)
   /* Check for the case where INSN does not have a valid luid.  In this case,
      there is no need to modify the regno_last_uid, as this can only happen
      when code is inserted after the loop_end to set a pseudo's final value,
-     and hence this insn will never be the last use of x.  */
+     and hence this insn will never be the last use of x.
+     ???? This comment is not correct.  See for example loop_givs_reduce.
+     This may insert an insn before another new insn.  */
   if (GET_CODE (x) == REG && REGNO (x) < max_reg_before_loop
       && INSN_UID (insn) < max_uid_for_loop
       && REGNO_LAST_LUID (REGNO (x)) < INSN_LUID (insn))
-    REGNO_LAST_UID (REGNO (x)) = INSN_UID (insn);
+    {
+      REGNO_LAST_UID (REGNO (x)) = INSN_UID (insn);
+    }
   else
     {
-      register int i, j;
-      register const char *fmt = GET_RTX_FORMAT (GET_CODE (x));
+      int i, j;
+      const char *fmt = GET_RTX_FORMAT (GET_CODE (x));
       for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
        {
          if (fmt[i] == 'e')
@@ -8254,14 +9302,14 @@ update_reg_last_use (x, insn)
    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 non-zero, then reverse the condition prior to canonizing it.
+   If REVERSE is nonzero, then reverse the condition prior to canonizing it.
 
-   If EARLIEST is non-zero, it is a pointer to a place where the earliest
+   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 non-zero, we wish the condition to be relative to that
+   If WANT_REG is nonzero, we wish the condition to be relative to that
    register, if possible.  Therefore, do not canonicalize the condition
    further.  */
 
@@ -8279,7 +9327,6 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
   rtx tem;
   rtx op0, op1;
   int reverse_code = 0;
-  int did_reverse_condition = 0;
   enum machine_mode mode;
 
   code = GET_CODE (cond);
@@ -8288,10 +9335,9 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
   op1 = XEXP (cond, 1);
 
   if (reverse)
-    {
-      code = reverse_condition (code);
-      did_reverse_condition ^= 1;
-    }
+    code = reversed_comparison_code (cond, insn);
+  if (code == UNKNOWN)
+    return 0;
 
   if (earliest)
     *earliest = insn;
@@ -8305,7 +9351,7 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
         && op1 == CONST0_RTX (GET_MODE (op0))
         && op0 != want_reg)
     {
-      /* Set non-zero when we find something of interest.  */
+      /* Set nonzero when we find something of interest.  */
       rtx x = 0;
 
 #ifdef HAVE_cc0
@@ -8342,15 +9388,24 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
 
       if ((prev = prev_nonnote_insn (prev)) == 0
          || GET_CODE (prev) != INSN
-         || FIND_REG_INC_NOTE (prev, 0)
-         || (set = single_set (prev)) == 0)
+         || 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 (rtx_equal_p (SET_DEST (set), op0))
+      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
@@ -8378,8 +9433,8 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
 #ifdef FLOAT_STORE_FLAG_VALUE
                     || (code == LT
                         && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                        && (REAL_VALUE_NEGATIVE
-                            (FLOAT_STORE_FLAG_VALUE (inner_mode))))
+                        && (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
+                            REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                     ))
                   && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'))
@@ -8398,8 +9453,8 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
 #ifdef FLOAT_STORE_FLAG_VALUE
                     || (code == GE
                         && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                        && (REAL_VALUE_NEGATIVE
-                            (FLOAT_STORE_FLAG_VALUE (inner_mode))))
+                        && (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
+                            REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                     ))
                   && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'
@@ -8408,10 +9463,6 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
                       || mode == VOIDmode || inner_mode == VOIDmode))
 
            {
-             /* We might have reversed a LT to get a GE here.  But this wasn't
-                actually the comparison of data, so we don't flag that we
-                have had to reverse the condition.  */
-             did_reverse_condition ^= 1;
              reverse_code = 1;
              x = SET_SRC (set);
            }
@@ -8429,10 +9480,9 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
            code = GET_CODE (x);
          if (reverse_code)
            {
-             code = reverse_condition (code);
+             code = reversed_comparison_code (x, prev);
              if (code == UNKNOWN)
                return 0;
-             did_reverse_condition ^= 1;
              reverse_code = 0;
            }
 
@@ -8468,7 +9518,7 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
        {
        case LE:
          if ((unsigned HOST_WIDE_INT) const_val != max_val >> 1)
-           code = LT, op1 = GEN_INT (const_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
@@ -8477,17 +9527,17 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
          if ((HOST_WIDE_INT) (const_val & max_val)
              != (((HOST_WIDE_INT) 1
                   << (GET_MODE_BITSIZE (GET_MODE (op0)) - 1))))
-           code = GT, op1 = GEN_INT (const_val - 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 (uconst_val + 1);
+           code = LTU, op1 = gen_int_mode (uconst_val + 1, GET_MODE (op0));
          break;
 
        case GEU:
          if (uconst_val != 0)
-           code = GTU, op1 = GEN_INT (uconst_val - 1);
+           code = GTU, op1 = gen_int_mode (uconst_val - 1, GET_MODE (op0));
          break;
 
        default:
@@ -8495,20 +9545,9 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
        }
     }
 
-  /* If this was floating-point and we reversed anything other than an
-     EQ or NE or (UN)ORDERED, return zero.  */
-  if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-      && did_reverse_condition
-      && code != NE && code != EQ && code != UNORDERED && code != ORDERED
-      && ! flag_fast_math
-      && GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
-    return 0;
-
-#ifdef HAVE_cc0
   /* Never return CC0; return zero instead.  */
-  if (op0 == cc0_rtx)
+  if (CC0_P (op0))
     return 0;
-#endif
 
   return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
 }
@@ -8518,7 +9557,7 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
    inequality floating-point comparison which needs to be reversed, 0 will
    be returned.
 
-   If EARLIEST is non-zero, it is a pointer to a place where the earliest
+   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.  */
@@ -8557,7 +9596,7 @@ get_condition_for_loop (loop, x)
      const struct loop *loop;
      rtx x;
 {
-  rtx comparison = get_condition (x, NULL_PTR);
+  rtx comparison = get_condition (x, (rtx*) 0);
 
   if (comparison == 0
       || ! loop_invariant_p (loop, XEXP (comparison, 0))
@@ -8663,65 +9702,152 @@ insert_loop_mem (mem, data)
   return 0;
 }
 
-/* Like load_mems, but also ensures that REGS->SET_IN_LOOP,
-   REGS->MAY_NOT_OPTIMIZE, REGS->SINGLE_USAGE, and INSN_COUNT have the correct
-   values after load_mems.  */
+
+/* Allocate REGS->ARRAY or reallocate it if it is too small.
+
+   Increment REGS->ARRAY[I].SET_IN_LOOP at the index I of each
+   register that is modified by an insn between FROM and TO.  If the
+   value of an element of REGS->array[I].SET_IN_LOOP becomes 127 or
+   more, stop incrementing it, to avoid overflow.
+
+   Store in REGS->ARRAY[I].SINGLE_USAGE the single insn in which
+   register I is used, if it is only used once.  Otherwise, it is set
+   to 0 (for no uses) or const0_rtx for more than one use.  This
+   parameter may be zero, in which case this processing is not done.
+
+   Set REGS->ARRAY[I].MAY_NOT_OPTIMIZE nonzero if we should not
+   optimize register I.  */
 
 static void
-load_mems_and_recount_loop_regs_set (loop, insn_count)
+loop_regs_scan (loop, extra_size)
      const struct loop *loop;
-     int *insn_count;
+     int extra_size;
 {
   struct loop_regs *regs = LOOP_REGS (loop);
-  int nregs = max_reg_num ();
+  int old_nregs;
+  /* last_set[n] is nonzero iff reg n has been set in the current
+   basic block.  In that case, it is the insn that last set reg n.  */
+  rtx *last_set;
+  rtx insn;
+  int i;
+
+  old_nregs = regs->num;
+  regs->num = max_reg_num ();
+
+  /* Grow the regs array if not allocated or too small.  */
+  if (regs->num >= regs->size)
+    {
+      regs->size = regs->num + extra_size;
+
+      regs->array = (struct loop_reg *)
+       xrealloc (regs->array, regs->size * sizeof (*regs->array));
+
+      /* Zero the new elements.  */
+      memset (regs->array + old_nregs, 0,
+             (regs->size - old_nregs) * sizeof (*regs->array));
+    }
+
+  /* Clear previously scanned fields but do not clear n_times_set.  */
+  for (i = 0; i < old_nregs; i++)
+    {
+      regs->array[i].set_in_loop = 0;
+      regs->array[i].may_not_optimize = 0;
+      regs->array[i].single_usage = NULL_RTX;
+    }
+
+  last_set = (rtx *) xcalloc (regs->num, sizeof (rtx));
+
+  /* Scan the loop, recording register usage.  */
+  for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
+       insn = NEXT_INSN (insn))
+    {
+      if (INSN_P (insn))
+       {
+         /* Record registers that have exactly one use.  */
+         find_single_use_in_loop (regs, insn, PATTERN (insn));
 
-  load_mems (loop);
+         /* Include uses in REG_EQUAL notes.  */
+         if (REG_NOTES (insn))
+           find_single_use_in_loop (regs, insn, REG_NOTES (insn));
 
-  /* Recalculate regs->set_in_loop and friends since load_mems may have
-     created new registers.  */
-  if (max_reg_num () > nregs)
-    {
-      int i;
-      int old_nregs;
+         if (GET_CODE (PATTERN (insn)) == SET
+             || GET_CODE (PATTERN (insn)) == CLOBBER)
+           count_one_set (regs, insn, PATTERN (insn), last_set);
+         else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+           {
+             int i;
+             for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+               count_one_set (regs, insn, XVECEXP (PATTERN (insn), 0, i),
+                              last_set);
+           }
+       }
 
-      old_nregs = nregs;
-      nregs = max_reg_num ();
+      if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
+       memset (last_set, 0, regs->num * sizeof (rtx));
 
-      if ((unsigned) nregs > regs->set_in_loop->num_elements)
+      /* Invalidate all registers used for function argument passing.
+        We check rtx_varies_p for the same reason as below, to allow
+        optimizing PIC calculations.  */
+      if (GET_CODE (insn) == CALL_INSN)
        {
-         /* Grow all the arrays.  */
-         VARRAY_GROW (regs->set_in_loop, nregs);
-         VARRAY_GROW (regs->n_times_set, nregs);
-         VARRAY_GROW (regs->may_not_optimize, nregs);
-         VARRAY_GROW (regs->single_usage, nregs);
-       }
-      /* Clear the arrays */
-      memset ((char *) &regs->set_in_loop->data, 0, nregs * sizeof (int));
-      memset ((char *) &regs->may_not_optimize->data, 0, nregs * sizeof (char));
-      memset ((char *) &regs->single_usage->data, 0, nregs * sizeof (rtx));
+         rtx link;
+         for (link = CALL_INSN_FUNCTION_USAGE (insn); 
+              link; 
+              link = XEXP (link, 1))
+           {
+             rtx op, reg;
 
-      count_loop_regs_set (loop, regs->may_not_optimize, regs->single_usage,
-                          insn_count, nregs);
+             if (GET_CODE (op = XEXP (link, 0)) == USE
+                 && GET_CODE (reg = XEXP (op, 0)) == REG
+                 && rtx_varies_p (reg, 1))
+               regs->array[REGNO (reg)].may_not_optimize = 1;
+           }
+       }
+    }
 
-      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+  /* Invalidate all hard registers clobbered by calls.  With one exception:
+     a call-clobbered PIC register is still function-invariant for our
+     purposes, since we can hoist any PIC calculations out of the loop.
+     Thus the call to rtx_varies_p.  */
+  if (LOOP_INFO (loop)->has_call)
+    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+      if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)
+         && rtx_varies_p (regno_reg_rtx[i], 1))
        {
-         VARRAY_CHAR (regs->may_not_optimize, i) = 1;
-         VARRAY_INT (regs->set_in_loop, i) = 1;
+         regs->array[i].may_not_optimize = 1;
+         regs->array[i].set_in_loop = 1;
        }
 
 #ifdef AVOID_CCMODE_COPIES
-      /* Don't try to move insns which set CC registers if we should not
-        create CCmode register copies.  */
-      for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
-       if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
-         VARRAY_CHAR (regs->may_not_optimize, i) = 1;
+  /* Don't try to move insns which set CC registers if we should not
+     create CCmode register copies.  */
+  for (i = regs->num - 1; i >= FIRST_PSEUDO_REGISTER; i--)
+    if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
+      regs->array[i].may_not_optimize = 1;
 #endif
 
-      /* Set regs->n_times_set for the new registers.  */
-      bcopy ((char *) (&regs->set_in_loop->data.i[0] + old_nregs),
-            (char *) (&regs->n_times_set->data.i[0] + old_nregs),
-            (nregs - old_nregs) * sizeof (int));
-    }
+  /* Set regs->array[I].n_times_set for the new registers.  */
+  for (i = old_nregs; i < regs->num; i++)
+    regs->array[i].n_times_set = regs->array[i].set_in_loop;
+
+  free (last_set);
+}
+
+/* Returns the number of real INSNs in the LOOP.  */
+
+static int
+count_insns_in_loop (loop)
+     const struct loop *loop;
+{
+  int count = 0;
+  rtx insn;
+
+  for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
+       insn = NEXT_INSN (insn))
+    if (INSN_P (insn))
+      ++count;
+
+  return count;
 }
 
 /* Move MEMs into registers for the duration of the loop.  */
@@ -8734,12 +9860,12 @@ load_mems (loop)
   struct loop_regs *regs = LOOP_REGS (loop);
   int maybe_never = 0;
   int i;
-  rtx p;
+  rtx p, prev_ebb_head;
   rtx label = NULL_RTX;
   rtx end_label;
   /* Nonzero if the next instruction may never be executed.  */
   int next_maybe_never = 0;
-  int last_max_reg = max_reg_num ();
+  unsigned int last_max_reg = max_reg_num ();
 
   if (loop_info->mems_idx == 0)
     return;
@@ -8753,7 +9879,7 @@ load_mems (loop)
      never executed.  Also check if there is a goto out of the loop other
      than right after the end of the loop.  */
   for (p = next_insn_in_loop (loop, loop->scan_start);
-       p != NULL_RTX && ! maybe_never;
+       p != NULL_RTX;
        p = next_insn_in_loop (loop, p))
     {
       if (GET_CODE (p) == CODE_LABEL)
@@ -8773,10 +9899,13 @@ load_mems (loop)
          /* If this is a jump outside of the loop but not right
             after the end of the loop, we would have to emit new fixup
             sequences for each such label.  */
-         if (JUMP_LABEL (p) != end_label
-             && (INSN_UID (JUMP_LABEL (p)) >= max_uid_for_loop
-                 || INSN_LUID (JUMP_LABEL (p)) < INSN_LUID (loop->start)
-                 || INSN_LUID (JUMP_LABEL (p)) > INSN_LUID (loop->end)))
+         if (/* If we can't tell where control might go when this
+                JUMP_INSN is executed, we must be conservative.  */
+             !JUMP_LABEL (p)
+             || (JUMP_LABEL (p) != end_label
+                 && (INSN_UID (JUMP_LABEL (p)) >= max_uid_for_loop
+                     || INSN_LUID (JUMP_LABEL (p)) < INSN_LUID (loop->start)
+                     || INSN_LUID (JUMP_LABEL (p)) > INSN_LUID (loop->end))))
            return;
 
          if (!any_condjump_p (p))
@@ -8796,6 +9925,7 @@ load_mems (loop)
        PREV_INSN (p) && GET_CODE (p) != CODE_LABEL;
        p = PREV_INSN (p))
     ;
+  prev_ebb_head = p;
 
   cselib_init ();
 
@@ -8886,7 +10016,7 @@ load_mems (loop)
       loop_info->mems[i].reg = reg;
 
       /* Now, replace all references to the MEM with the
-        corresponding pesudos.  */
+        corresponding pseudos.  */
       maybe_never = 0;
       for (p = next_insn_in_loop (loop, loop->scan_start);
           p != NULL_RTX;
@@ -8907,8 +10037,7 @@ load_mems (loop)
                  && GET_CODE (SET_DEST (set)) == REG
                  && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
                  && REGNO (SET_DEST (set)) < last_max_reg
-                 && VARRAY_INT (regs->n_times_set,
-                                REGNO (SET_DEST (set))) == 1
+                 && regs->array[REGNO (SET_DEST (set))].n_times_set == 1
                  && rtx_equal_p (SET_SRC (set), mem))
                SET_REGNO_REG_SET (&load_copies, REGNO (SET_DEST (set)));
 
@@ -8922,13 +10051,24 @@ load_mems (loop)
                  && GET_CODE (SET_SRC (set)) == REG
                  && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER
                  && REGNO (SET_SRC (set)) < last_max_reg
-                 && VARRAY_INT (regs->n_times_set, REGNO (SET_SRC (set))) == 1
+                 && regs->array[REGNO (SET_SRC (set))].n_times_set == 1
                  && rtx_equal_p (SET_DEST (set), mem))
                SET_REGNO_REG_SET (&store_copies, REGNO (SET_SRC (set)));
 
-             /* Replace the memory reference with the shadow register.  */
-             replace_loop_mems (p, loop_info->mems[i].mem,
-                                loop_info->mems[i].reg);
+             /* If this is a call which uses / clobbers this memory
+                location, we must not change the interface here.  */
+             if (GET_CODE (p) == CALL_INSN
+                 && reg_mentioned_p (loop_info->mems[i].mem,
+                                     CALL_INSN_FUNCTION_USAGE (p)))
+               {
+                 cancel_changes (0);
+                 loop_info->mems[i].optimize = 0;
+                 break;
+               }
+             else
+               /* Replace the memory reference with the shadow register.  */
+               replace_loop_mems (p, loop_info->mems[i].mem,
+                                  loop_info->mems[i].reg, written);
            }
 
          if (GET_CODE (p) == CODE_LABEL
@@ -8936,7 +10076,9 @@ load_mems (loop)
            maybe_never = 1;
        }
 
-      if (! apply_change_group ())
+      if (! loop_info->mems[i].optimize)
+       ; /* We found we couldn't do the replacement, so do nothing.  */
+      else if (! apply_change_group ())
        /* We couldn't replace all occurrences of the MEM.  */
        loop_info->mems[i].optimize = 0;
       else
@@ -8958,7 +10100,7 @@ load_mems (loop)
                  if (CONSTANT_P (equiv->loc))
                    const_equiv = equiv;
                  else if (GET_CODE (equiv->loc) == REG
-                          /* Extending hard register lifetimes cuases crash
+                          /* Extending hard register lifetimes causes crash
                              on SRC targets.  Doing so on non-SRC is
                              probably also not good idea, since we most
                              probably have pseudoregister equivalence as
@@ -8984,12 +10126,21 @@ load_mems (loop)
              if (best_equiv)
                best = copy_rtx (best_equiv->loc);
            }
+
          set = gen_move_insn (reg, best);
-         set = emit_insn_before (set, loop->start);
+         set = loop_insn_hoist (loop, set);
+         if (REG_P (best))
+           {
+             for (p = prev_ebb_head; p != loop->start; p = NEXT_INSN (p))
+               if (REGNO_LAST_UID (REGNO (best)) == INSN_UID (p))
+                 {
+                   REGNO_LAST_UID (REGNO (best)) = INSN_UID (set);
+                   break;
+                 }
+           }
+
          if (const_equiv)
-           REG_NOTES (set) = gen_rtx_EXPR_LIST (REG_EQUAL,
-                                                copy_rtx (const_equiv->loc),
-                                                REG_NOTES (set));
+           set_unique_reg_note (set, REG_EQUAL, copy_rtx (const_equiv->loc));
 
          if (written)
            {
@@ -9002,7 +10153,7 @@ load_mems (loop)
              /* Store the memory immediately after END, which is
                 the NOTE_LOOP_END.  */
              set = gen_move_insn (copy_rtx (mem), reg);
-             emit_insn_after (set, label);
+             loop_insn_emit_after (loop, 0, label, set);
            }
 
          if (loop_dump_stream)
@@ -9036,22 +10187,14 @@ load_mems (loop)
     {
       /* Now, we need to replace all references to the previous exit
         label with the new one.  */
-      rtx_pair rr;
+      replace_label_data rr;
       rr.r1 = end_label;
       rr.r2 = label;
+      rr.update_label_nuses = true;
 
       for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
        {
          for_each_rtx (&p, replace_label, &rr);
-
-         /* If this is a JUMP_INSN, then we also need to fix the JUMP_LABEL
-            field.  This is not handled by for_each_rtx because it doesn't
-            handle unprinted ('0') fields.  We need to update JUMP_LABEL
-            because the immediately following unroll pass will use it.
-            replace_label would not work anyways, because that only handles
-            LABEL_REFs.  */
-         if (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == end_label)
-           JUMP_LABEL (p) = label;
        }
     }
 
@@ -9138,7 +10281,16 @@ try_copy_prop (loop, replacement, regno)
          arg.set_seen = 0;
          note_stores (PATTERN (insn), note_reg_stored, &arg);
          if (arg.set_seen)
-           break;
+           {
+             rtx note = find_reg_note (insn, REG_EQUAL, NULL);
+
+             /* It is possible that we've turned previously valid REG_EQUAL to
+                invalid, as we change the REGNO to REPLACEMENT and unlike REGNO,
+                REPLACEMENT is modified, we get different meaning.  */
+             if (note && reg_mentioned_p (replacement, XEXP (note, 0)))
+               remove_note (insn, note);
+             break;
+           }
        }
     }
   if (! init_insn)
@@ -9149,17 +10301,51 @@ try_copy_prop (loop, replacement, regno)
        fprintf (loop_dump_stream, "  Replaced reg %d", regno);
       if (store_is_first && replaced_last)
        {
-         PUT_CODE (init_insn, NOTE);
-         NOTE_LINE_NUMBER (init_insn) = NOTE_INSN_DELETED;
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream, ", deleting init_insn (%d)",
-                    INSN_UID (init_insn));
+         rtx first;
+         rtx retval_note;
+
+         /* Assume we're just deleting INIT_INSN.  */
+         first = init_insn;
+         /* Look for REG_RETVAL note.  If we're deleting the end of
+            the libcall sequence, the whole sequence can go.  */
+         retval_note = find_reg_note (init_insn, REG_RETVAL, NULL_RTX);
+         /* If we found a REG_RETVAL note, find the first instruction
+            in the sequence.  */
+         if (retval_note)
+           first = XEXP (retval_note, 0);
+
+         /* Delete the instructions.  */
+         loop_delete_insns (first, init_insn);
        }
       if (loop_dump_stream)
        fprintf (loop_dump_stream, ".\n");
     }
 }
 
+/* Replace all the instructions from FIRST up to and including LAST
+   with NOTE_INSN_DELETED notes.  */
+
+static void
+loop_delete_insns (first, last)
+     rtx first;
+     rtx last;
+{
+  while (1)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream, ", deleting init_insn (%d)",
+                INSN_UID (first));
+      delete_insn (first);
+
+      /* If this was the LAST instructions we're supposed to delete,
+        we're done.  */
+      if (first == last)
+       break;
+
+      first = NEXT_INSN (first);
+    }
+}
+
 /* Try to replace occurrences of pseudo REGNO with REPLACEMENT within
    loop LOOP if the order of the sets of these registers can be
    swapped.  There must be exactly one insn within the loop that sets
@@ -9172,7 +10358,7 @@ try_swap_copy_prop (loop, replacement, regno)
      unsigned int regno;
 {
   rtx insn;
-  rtx set;
+  rtx set = NULL_RTX;
   unsigned int new_regno;
 
   new_regno = REGNO (replacement);
@@ -9182,7 +10368,7 @@ try_swap_copy_prop (loop, replacement, regno)
        insn = next_insn_in_loop (loop, insn))
     {
       /* Search for the insn that copies REGNO to NEW_REGNO?  */
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+      if (INSN_P (insn)
          && (set = single_set (insn))
          && GET_CODE (SET_DEST (set)) == REG
          && REGNO (SET_DEST (set)) == new_regno
@@ -9202,7 +10388,7 @@ try_swap_copy_prop (loop, replacement, regno)
 
       prev_insn = PREV_INSN (insn);
 
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+      if (INSN_P (insn)
          && (prev_set = single_set (prev_insn))
          && GET_CODE (SET_DEST (prev_set)) == REG
          && REGNO (SET_DEST (prev_set)) == regno)
@@ -9247,6 +10433,33 @@ try_swap_copy_prop (loop, replacement, regno)
     }
 }
 
+/* Worker function for find_mem_in_note, called via for_each_rtx.  */
+
+static int
+find_mem_in_note_1 (x, data)
+     rtx *x;
+     void *data;
+{
+  if (*x != NULL_RTX && GET_CODE (*x) == MEM)
+    {
+      rtx *res = (rtx *) data;
+      *res = *x;
+      return 1;
+    }
+  return 0;
+}
+
+/* Returns the first MEM found in NOTE by depth-first search.  */
+
+static rtx
+find_mem_in_note (note)
+     rtx note;
+{
+  if (note && for_each_rtx (&note, find_mem_in_note_1, &note))
+    return note;
+  return NULL_RTX;
+}
+  
 /* Replace MEM with its associated pseudo register.  This function is
    called from load_mems via for_each_rtx.  DATA is actually a pointer
    to a structure describing the instruction currently being scanned
@@ -9289,10 +10502,11 @@ replace_loop_mem (mem, data)
 }
 
 static void
-replace_loop_mems (insn, mem, reg)
+replace_loop_mems (insn, mem, reg, written)
      rtx insn;
      rtx mem;
      rtx reg;
+     int written;
 {
   loop_replace_args args;
 
@@ -9301,6 +10515,26 @@ replace_loop_mems (insn, mem, reg)
   args.replacement = reg;
 
   for_each_rtx (&insn, replace_loop_mem, &args);
+
+  /* If we hoist a mem write out of the loop, then REG_EQUAL
+     notes referring to the mem are no longer valid.  */
+  if (written)
+    {
+      rtx note, sub;
+      rtx *link;
+
+      for (link = &REG_NOTES (insn); (note = *link); link = &XEXP (note, 1))
+       {
+         if (REG_NOTE_KIND (note) == REG_EQUAL
+             && (sub = find_mem_in_note (note))
+             && true_dependence (mem, VOIDmode, sub, rtx_varies_p))
+           {
+             /* Remove the note.  */
+             validate_change (NULL_RTX, link, XEXP (note, 1), 1);
+             break;
+           }
+       }
+    }
 }
 
 /* Replace one register with another.  Called through for_each_rtx; PX points
@@ -9338,36 +10572,328 @@ replace_loop_regs (insn, reg, replacement)
 
   for_each_rtx (&insn, replace_loop_reg, &args);
 }
+\f
+/* Emit insn for PATTERN after WHERE_INSN in basic block WHERE_BB
+   (ignored in the interim).  */
 
-/* Replace occurrences of the old exit label for the loop with the new
-   one.  DATA is an rtx_pair containing the old and new labels,
-   respectively.  */
+static rtx
+loop_insn_emit_after (loop, where_bb, where_insn, pattern)
+     const struct loop *loop ATTRIBUTE_UNUSED;
+     basic_block where_bb ATTRIBUTE_UNUSED;
+     rtx where_insn;
+     rtx pattern;
+{
+  return emit_insn_after (pattern, where_insn);
+}
 
-static int
-replace_label (x, data)
-     rtx *x;
-     void *data;
+
+/* If WHERE_INSN is nonzero emit insn for PATTERN before WHERE_INSN
+   in basic block WHERE_BB (ignored in the interim) within the loop
+   otherwise hoist PATTERN into the loop pre-header.  */
+
+rtx
+loop_insn_emit_before (loop, where_bb, where_insn, pattern)
+     const struct loop *loop;
+     basic_block where_bb ATTRIBUTE_UNUSED;
+     rtx where_insn;
+     rtx pattern;
 {
-  rtx l = *x;
-  rtx old_label = ((rtx_pair *) data)->r1;
-  rtx new_label = ((rtx_pair *) data)->r2;
+  if (! where_insn)
+    return loop_insn_hoist (loop, pattern);
+  return emit_insn_before (pattern, where_insn);
+}
 
-  if (l == NULL_RTX)
-    return 0;
 
-  if (GET_CODE (l) != LABEL_REF)
-    return 0;
+/* Emit call insn for PATTERN before WHERE_INSN in basic block
+   WHERE_BB (ignored in the interim) within the loop.  */
 
-  if (XEXP (l, 0) != old_label)
-    return 0;
+static rtx
+loop_call_insn_emit_before (loop, where_bb, where_insn, pattern)
+     const struct loop *loop ATTRIBUTE_UNUSED;
+     basic_block where_bb ATTRIBUTE_UNUSED;
+     rtx where_insn;
+     rtx pattern;
+{
+  return emit_call_insn_before (pattern, where_insn);
+}
 
-  XEXP (l, 0) = new_label;
-  ++LABEL_NUSES (new_label);
-  --LABEL_NUSES (old_label);
 
-  return 0;
+/* Hoist insn for PATTERN into the loop pre-header.  */
+
+rtx
+loop_insn_hoist (loop, pattern)
+     const struct loop *loop;
+     rtx pattern;
+{
+  return loop_insn_emit_before (loop, 0, loop->start, pattern);
+}
+
+
+/* Hoist call insn for PATTERN into the loop pre-header.  */
+
+static rtx
+loop_call_insn_hoist (loop, pattern)
+     const struct loop *loop;
+     rtx pattern;
+{
+  return loop_call_insn_emit_before (loop, 0, loop->start, pattern);
+}
+
+
+/* Sink insn for PATTERN after the loop end.  */
+
+rtx
+loop_insn_sink (loop, pattern)
+     const struct loop *loop;
+     rtx pattern;
+{
+  return loop_insn_emit_before (loop, 0, loop->sink, pattern);
+}
+
+/* bl->final_value can be eighter general_operand or PLUS of general_operand
+   and constant.  Emit sequence of instructions to load it into REG.  */
+static rtx
+gen_load_of_final_value (reg, final_value)
+     rtx reg, final_value;
+{
+  rtx seq;
+  start_sequence ();
+  final_value = force_operand (final_value, reg);
+  if (final_value != reg)
+    emit_move_insn (reg, final_value);
+  seq = get_insns ();
+  end_sequence ();
+  return seq;
+}
+
+/* If the loop has multiple exits, emit insn for PATTERN before the
+   loop to ensure that it will always be executed no matter how the
+   loop exits.  Otherwise, emit the insn for PATTERN after the loop,
+   since this is slightly more efficient.  */
+
+static rtx
+loop_insn_sink_or_swim (loop, pattern)
+     const struct loop *loop;
+     rtx pattern;
+{
+  if (loop->exit_count)
+    return loop_insn_hoist (loop, pattern);
+  else
+    return loop_insn_sink (loop, pattern);
 }
 \f
+static void
+loop_ivs_dump (loop, file, verbose)
+     const struct loop *loop;
+     FILE *file;
+     int verbose;
+{
+  struct iv_class *bl;
+  int iv_num = 0;
+
+  if (! loop || ! file)
+    return;
+
+  for (bl = LOOP_IVS (loop)->list; bl; bl = bl->next)
+    iv_num++;
+
+  fprintf (file, "Loop %d: %d IV classes\n", loop->num, iv_num);
+
+  for (bl = LOOP_IVS (loop)->list; bl; bl = bl->next)
+    {
+      loop_iv_class_dump (bl, file, verbose);
+      fputc ('\n', file);
+    }
+}
+
+
+static void
+loop_iv_class_dump (bl, file, verbose)
+     const struct iv_class *bl;
+     FILE *file;
+     int verbose ATTRIBUTE_UNUSED;
+{
+  struct induction *v;
+  rtx incr;
+  int i;
+
+  if (! bl || ! file)
+    return;
+
+  fprintf (file, "IV class for reg %d, benefit %d\n",
+          bl->regno, bl->total_benefit);
+
+  fprintf (file, " Init insn %d", INSN_UID (bl->init_insn));
+  if (bl->initial_value)
+    {
+      fprintf (file, ", init val: ");
+      print_simple_rtl (file, bl->initial_value);
+    }
+  if (bl->initial_test)
+    {
+      fprintf (file, ", init test: ");
+      print_simple_rtl (file, bl->initial_test);
+    }
+  fputc ('\n', file);
+
+  if (bl->final_value)
+    {
+      fprintf (file, " Final val: ");
+      print_simple_rtl (file, bl->final_value);
+      fputc ('\n', file);
+    }
+
+  if ((incr = biv_total_increment (bl)))
+    {
+      fprintf (file, " Total increment: ");
+      print_simple_rtl (file, incr);
+      fputc ('\n', file);
+    }
+
+  /* List the increments.  */
+  for (i = 0, v = bl->biv; v; v = v->next_iv, i++)
+    {
+      fprintf (file, " Inc%d: insn %d, incr: ", i, INSN_UID (v->insn));
+      print_simple_rtl (file, v->add_val);
+      fputc ('\n', file);
+    }
+
+  /* List the givs.  */
+  for (i = 0, v = bl->giv; v; v = v->next_iv, i++)
+    {
+      fprintf (file, " Giv%d: insn %d, benefit %d, ",
+              i, INSN_UID (v->insn), v->benefit);
+      if (v->giv_type == DEST_ADDR)
+       print_simple_rtl (file, v->mem);
+      else
+       print_simple_rtl (file, single_set (v->insn));
+      fputc ('\n', file);
+    }
+}
+
+
+static void
+loop_biv_dump (v, file, verbose)
+     const struct induction *v;
+     FILE *file;
+     int verbose;
+{
+  if (! v || ! file)
+    return;
+
+  fprintf (file,
+          "Biv %d: insn %d",
+          REGNO (v->dest_reg), INSN_UID (v->insn));
+  fprintf (file, " const ");
+  print_simple_rtl (file, v->add_val);
+
+  if (verbose && v->final_value)
+    {
+      fputc ('\n', file);
+      fprintf (file, " final ");
+      print_simple_rtl (file, v->final_value);
+    }
+
+  fputc ('\n', file);
+}
+
+
+static void
+loop_giv_dump (v, file, verbose)
+     const struct induction *v;
+     FILE *file;
+     int verbose;
+{
+  if (! v || ! file)
+    return;
+
+  if (v->giv_type == DEST_REG)
+    fprintf (file, "Giv %d: insn %d",
+            REGNO (v->dest_reg), INSN_UID (v->insn));
+  else
+    fprintf (file, "Dest address: insn %d",
+            INSN_UID (v->insn));
+
+  fprintf (file, " src reg %d benefit %d",
+          REGNO (v->src_reg), v->benefit);
+  fprintf (file, " lifetime %d",
+          v->lifetime);
+
+  if (v->replaceable)
+    fprintf (file, " replaceable");
+
+  if (v->no_const_addval)
+    fprintf (file, " ncav");
+
+  if (v->ext_dependent)
+    {
+      switch (GET_CODE (v->ext_dependent))
+       {
+       case SIGN_EXTEND:
+         fprintf (file, " ext se");
+         break;
+       case ZERO_EXTEND:
+         fprintf (file, " ext ze");
+         break;
+       case TRUNCATE:
+         fprintf (file, " ext tr");
+         break;
+       default:
+         abort ();
+       }
+    }
+
+  fputc ('\n', file);
+  fprintf (file, " mult ");
+  print_simple_rtl (file, v->mult_val);
+
+  fputc ('\n', file);
+  fprintf (file, " add  ");
+  print_simple_rtl (file, v->add_val);
+
+  if (verbose && v->final_value)
+    {
+      fputc ('\n', file);
+      fprintf (file, " final ");
+      print_simple_rtl (file, v->final_value);
+    }
+
+  fputc ('\n', file);
+}
+
+
+void
+debug_ivs (loop)
+     const struct loop *loop;
+{
+  loop_ivs_dump (loop, stderr, 1);
+}
+
+
+void
+debug_iv_class (bl)
+     const struct iv_class *bl;
+{
+  loop_iv_class_dump (bl, stderr, 1);
+}
+
+
+void
+debug_biv (v)
+     const struct induction *v;
+{
+  loop_biv_dump (v, stderr, 1);
+}
+
+
+void
+debug_giv (v)
+     const struct induction *v;
+{
+  loop_giv_dump (v, stderr, 1);
+}
+
+
 #define LOOP_BLOCK_NUM_1(INSN) \
 ((INSN) ? (BLOCK_FOR_INSN (INSN) ? BLOCK_NUM (INSN) : - 1) : -1)