OSDN Git Service

Fix copyright problems reported by Doug Evans.
[pf3gnuchains/gcc-fork.git] / gcc / loop.c
index 0ab16d6..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,109 @@ 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.
    The luids are like uids but increase monotonically always.
@@ -69,38 +172,17 @@ 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.  */
 
 static int max_loop_num;
 
-
-
-
 /* Bound on pseudo register number before loop optimization.
    A pseudo has valid regscan info if its number is < max_reg_before_loop.  */
 unsigned int max_reg_before_loop;
 
 /* The value to pass to the next call of reg_scan_update.  */
 static int loop_max_reg;
-
-/* This obstack is used in product_cheap_p to allocate its rtl.  It
-   may call gen_reg_rtx which, in turn, may reallocate regno_reg_rtx.
-   If we used the same obstack that it did, we would be deallocating
-   that array.  */
-
-static struct obstack temp_obstack;
-
-/* This is where the pointer to the obstack being used for RTL is stored.  */
-
-extern struct obstack *rtl_obstack;
-
-#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.
@@ -122,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 */
@@ -138,31 +223,20 @@ 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;
 };
 
-struct movables
-{
-  /* Head of movable chain.  */
-  struct movable *head;
-  /* Last movable in chain.  */
-  struct movable *last;
-  /* Number of movables in the loop.  */
-  int num;
-};
-
-static struct movables the_movables;
 
 FILE *loop_dump_stream;
 
 /* Forward declarations.  */
 
-static void verify_dominator PARAMS ((struct loop *));
+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 *));
@@ -170,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));
@@ -185,18 +254,37 @@ static void replace_call_address PARAMS ((rtx, rtx, rtx));
 #endif
 static rtx skip_consec_insns PARAMS ((rtx, int));
 static int libcall_benefit PARAMS ((rtx));
-static void ignore_some_movables PARAMS ((struct movables *));
-static void force_movables PARAMS ((struct movables *));
-static void combine_movables PARAMS ((struct movables *, struct loop_regs *));
-static int regs_match_p PARAMS ((rtx, rtx, struct movables *));
-static int rtx_equal_for_loop_p PARAMS ((rtx, rtx, struct movables *, 
+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 *));
 static void add_label_notes PARAMS ((rtx, rtx));
-static void move_movables PARAMS ((struct loop *loop, struct movables *,
+static void move_movables PARAMS ((struct loop *loop, struct loop_movables *,
                                   int, int));
+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 *,
@@ -204,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,
@@ -222,46 +314,55 @@ static int consec_sets_giv PARAMS ((const struct loop *, int, rtx,
 static int check_dbra_loop PARAMS ((struct loop *, int));
 static rtx express_from_1 PARAMS ((rtx, rtx, rtx));
 static rtx combine_givs_p PARAMS ((struct induction *, struct induction *));
+static int cmp_combine_givs_stats PARAMS ((const PTR, const PTR));
 static void combine_givs PARAMS ((struct loop_regs *, struct iv_class *));
-struct recombine_givs_stats;
-static int find_life_end PARAMS ((const struct loop *, rtx, 
-                                 struct recombine_givs_stats *,
-                                 rtx, rtx));
-static void recombine_givs PARAMS ((const struct loop *, struct iv_class *,
-                                   int));
 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 *));
-
-typedef struct rtx_pair {
-  rtx r1;
-  rtx r2;
-} rtx_pair;
+void debug_loops PARAMS ((const struct loops *));
 
 typedef struct loop_replace_args
 {
@@ -271,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))
 
@@ -283,7 +384,8 @@ static int indirect_jump_in_function_p PARAMS ((rtx));
 static int compute_luids PARAMS ((rtx, rtx, int));
 
 static int biv_elimination_giv_has_0_offset PARAMS ((struct induction *,
-                                                  struct induction *, rtx));
+                                                    struct induction *,
+                                                    rtx));
 \f
 /* Benefit penalty, if a giv is not replaceable, i.e. must emit an insn to
    copy the value of the strength reduced giv to its original register.  */
@@ -295,18 +397,11 @@ static int reg_address_cost;
 void
 init_loop ()
 {
-  char *free_point = (char *) oballoc (1);
   rtx reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
 
   reg_address_cost = address_cost (reg, SImode);
 
   copy_cost = COSTS_N_INSNS (1);
-
-  /* Free the objects we just allocated.  */
-  obfree (free_point);
-
-  /* Initialize the obstack used for rtl in product_cheap_p.  */
-  gcc_obstack_init (&temp_obstack);
 }
 \f
 /* Compute the mapping from uids to luids.
@@ -350,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;
 
@@ -382,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;
@@ -402,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
@@ -427,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
@@ -453,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);
@@ -523,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;
@@ -532,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;
@@ -541,7 +620,7 @@ scan_loop (loop, flags)
   /* The SET from an insn, if it is the only SET in the insn.  */
   rtx set, set1;
   /* Chain describing insns movable in current loop.  */
-  struct movables *movables = &the_movables;
+  struct loop_movables *movables = LOOP_MOVABLES (loop);
   /* 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
@@ -549,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
@@ -584,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);
@@ -593,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
@@ -630,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)
     {
@@ -678,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.
@@ -690,302 +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
+               {
+                 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);
+                   }
+               }
+
+             /* 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)
                {
-                 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);
+                 for (i = 0; i < XVECLEN (PATTERN (p), 0); i++)
+                   {
+                     rtx x = XVECEXP (PATTERN (p), 0, i);
+                     if (GET_CODE (x) == USE)
+                       dependencies
+                         = gen_rtx_EXPR_LIST (VOIDmode, XEXP (x, 0),
+                                              dependencies);
+                   }
                }
-           }
 
-         /* Don't try to optimize a register that was made
-            by loop-optimization for an inner loop.
-            We don't know its life-span, so we can't compute the benefit.  */
-         if (REGNO (SET_DEST (set)) >= max_reg_before_loop)
-           ;
-         else if (/* The register is used in basic blocks other
+             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 *) alloca (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 = (uid_luid[REGNO_LAST_UID (regno)]
-                          > INSN_LUID (loop_end)
-                          || uid_luid[REGNO_FIRST_UID (regno)] < INSN_LUID (loop_start));
-             m->match = 0;
-             m->lifetime = (uid_luid[REGNO_LAST_UID (regno)]
-                            - uid_luid[REGNO_FIRST_UID (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.  */
-             if (movables->head == 0)
-               movables->head = m;
-             else
-               movables->last->next = m;
-             movables->last = 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
-                              || (uid_luid[REGNO_LAST_UID (regno)]
-                                  > INSN_LUID (loop_end))
-                              || (uid_luid[REGNO_FIRST_UID (regno)]
-                                  < INSN_LUID (p))
-                              || (labels_in_range_p
-                                  (p, uid_luid[REGNO_FIRST_UID (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 = (uid_luid[REGNO_LAST_UID (regno)]
-                                - uid_luid[REGNO_FIRST_UID (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.  */
-                 if (movables->head == 0)
-                   movables->head = m;
-                 else
-                   movables->last->next = m;
-                 movables->last = m;
+                 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
@@ -998,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;
@@ -1036,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)
@@ -1071,20 +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);
     }
 
-  VARRAY_FREE (regs->single_usage);
-  VARRAY_FREE (regs->set_in_loop);
-  VARRAY_FREE (regs->n_times_set);
-  VARRAY_FREE (regs->may_not_optimize);
+
+  /* The movable information is required for strength reduction.  */
+  loop_movables_free (movables);
+
+  free (regs->array);
+  regs->array = 0;
+  regs->num = 0;
 }
 \f
 /* Add elements to *OUTPUT to record all the pseudo-regs
@@ -1280,9 +1399,9 @@ skip_consec_insns (insn, count)
 
 static void
 ignore_some_movables (movables)
-     struct movables *movables;
+     struct loop_movables *movables;
 {
-  register struct movable *m, *m1;
+  struct movable *m, *m1;
 
   for (m = movables->head; m; m = m->next)
     {
@@ -1312,9 +1431,10 @@ ignore_some_movables (movables)
 
 static void
 force_movables (movables)
-     struct 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)
@@ -1351,32 +1471,38 @@ force_movables (movables)
 
 static void
 combine_movables (movables, regs)
-     struct movables *movables;
+     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;
 
-       bzero (matched_regs, regs->num);
+       memset (matched_regs, 0, regs->num);
        matched_regs[regno] = 1;
 
        /* 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.  */
@@ -1419,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.  */
@@ -1427,9 +1553,10 @@ combine_movables (movables, regs)
        if (m->partial && ! m->global
            && mode == GET_MODE (SET_SRC (PATTERN (NEXT_INSN (m->insn)))))
          {
-           register struct movable *m1;
-           int first = uid_luid[REGNO_FIRST_UID (m->regno)];
-           int last = uid_luid[REGNO_LAST_UID (m->regno)];
+           struct movable *m1;
+
+           int first = REGNO_FIRST_LUID (m->regno);
+           int last = REGNO_LAST_LUID (m->regno);
 
            if (m0 == 0)
              {
@@ -1447,8 +1574,8 @@ combine_movables (movables, regs)
               already combined together.  */
            for (m1 = movables->head; m1 != m; m1 = m1->next)
              if (m1 == m0 || (m1->partial && m1->match == m0))
-               if (! (uid_luid[REGNO_FIRST_UID (m1->regno)] > last
-                      || uid_luid[REGNO_LAST_UID (m1->regno)] < first))
+               if (! (REGNO_FIRST_LUID (m1->regno) > last
+                      || REGNO_LAST_LUID (m1->regno) < first))
                  goto overlap;
 
            /* No overlap: we can combine this with the others.  */
@@ -1465,13 +1592,31 @@ 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.  */
 
 static int
 regs_match_p (x, y, movables)
      rtx x, y;
-     struct movables *movables;
+     struct loop_movables *movables;
 {
   unsigned int xn = REGNO (x);
   unsigned int yn = REGNO (y);
@@ -1500,14 +1645,14 @@ regs_match_p (x, y, movables)
 static int
 rtx_equal_for_loop_p (x, y, movables, regs)
      rtx x, y;
-     struct movables *movables;
+     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;
@@ -1518,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)
@@ -1526,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)
@@ -1614,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)
@@ -1635,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);
@@ -1657,15 +1806,15 @@ add_label_notes (x, insns)
 static void
 move_movables (loop, movables, threshold, insn_count)
      struct loop *loop;
-     struct movables *movables;
+     struct loop_movables *movables;
      int threshold;
      int 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
@@ -1674,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.  */
@@ -1704,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.  */
 
@@ -1721,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.
@@ -1734,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
@@ -1753,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.  */
 
@@ -1774,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.  */
@@ -1798,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.
@@ -1830,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));
@@ -1925,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.  */
@@ -1940,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)
@@ -1961,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),
@@ -1971,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.  */
@@ -1987,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
@@ -2050,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 (uid_luid[REGNO_FIRST_UID (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 (uid_luid[REGNO_LAST_UID (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.  */
 
@@ -2111,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.  */
@@ -2129,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)
@@ -2160,6 +2352,34 @@ move_movables (loop, movables, threshold, insn_count)
   free (reg_map);
   free (already_moved);
 }
+
+
+static void
+loop_movables_add (movables, m)
+     struct loop_movables *movables;
+     struct movable *m;
+{
+  if (movables->head == 0)
+    movables->head = m;
+  else
+    movables->last->next = m;
+  movables->last = m;
+}
+
+
+static void
+loop_movables_free (movables)
+     struct loop_movables *movables;
+{
+  struct movable *m;
+  struct movable *m_next;
+
+  for (m = movables->head; m; m = m_next)
+    {
+      m_next = m->next;
+      free (m);
+    }
+}
 \f
 #if 0
 /* Scan X and replace the address of any MEM in it with ADDR.
@@ -2169,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;
@@ -2217,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);
        }
@@ -2233,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)
@@ -2270,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));
        }
@@ -2279,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.  */
@@ -2288,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;
@@ -2300,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;
@@ -2312,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;
@@ -2325,81 +2561,125 @@ 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 (volatile_refs_p (PATTERN (insn)))
-           loop_info->has_volatile = 1;
+         if (can_throw_internal (insn))
+           loop_info->has_multiple_exit_targets = 1;
 
-         if (GET_CODE (insn) == JUMP_INSN
-             && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
-                 || GET_CODE (PATTERN (insn)) == ADDR_VEC))
-           loop_info->has_tablejump = 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);
 
-         note_stores (PATTERN (insn), note_addr_stored, loop_info);
-         if (! loop_info->first_loop_store_insn && loop_info->store_mems)
-           loop_info->first_loop_store_insn = insn;
+               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;
 
-         if (! loop_info->has_multiple_exit_targets
-             && GET_CODE (insn) == JUMP_INSN
-             && GET_CODE (PATTERN (insn)) == SET
-             && SET_DEST (PATTERN (insn)) == pc_rtx)
+       case JUMP_INSN:
+         if (! loop_info->has_multiple_exit_targets)
            {
-             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));
-               }
+             rtx set = pc_set (insn);
 
-             do
+             if (set)
                {
-                 if (label1 && label1 != pc_rtx)
+                 rtx src = SET_SRC (set);
+                 rtx label1, label2;
+
+                 if (GET_CODE (src) == IF_THEN_ELSE)
                    {
-                     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))
+                     label1 = XEXP (src, 1);
+                     label2 = XEXP (src, 2);
+                   }
+                 else
+                   {
+                     label1 = src;
+                     label2 = NULL_RTX;
+                   }
+
+                 do
+                   {
+                     if (label1 && label1 != pc_rtx)
                        {
-                         /* A jump outside the current loop.  */
-                         loop_info->has_multiple_exit_targets = 1;
-                         break;
+                         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;
+                     label1 = label2;
+                     label2 = NULL_RTX;
+                   }
+                 while (label1);
+               }
+             else
+               {
+                 /* A return, or something tricky.  */
+                 loop_info->has_multiple_exit_targets = 1;
                }
-             while (label1);
            }
+         /* FALLTHRU */
+
+       case INSN:
+         if (volatile_refs_p (PATTERN (insn)))
+           loop_info->has_volatile = 1;
+
+         if (GET_CODE (insn) == JUMP_INSN
+             && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
+                 || GET_CODE (PATTERN (insn)) == ADDR_VEC))
+           loop_info->has_tablejump = 1;
+
+         note_stores (PATTERN (insn), note_addr_stored, loop_info);
+         if (! loop_info->first_loop_store_insn && loop_info->store_mems)
+           loop_info->first_loop_store_insn = insn;
+
+         if (flag_non_call_exceptions && can_throw_internal (insn))
+           loop_info->has_multiple_exit_targets = 1;
+         break;
+
+       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
@@ -2419,7 +2699,7 @@ prescan_loop (loop)
     {
       rtx mem = gen_rtx_MEM (BLKmode, const0_rtx);
 
-      loop_info->store_mems 
+      loop_info->store_mems
        = gen_rtx_EXPR_LIST (VOIDmode, mem, loop_info->store_mems);
     }
   if (loop_info->unknown_constant_address_altered)
@@ -2427,61 +2707,20 @@ prescan_loop (loop)
       rtx mem = gen_rtx_MEM (BLKmode, const0_rtx);
 
       RTX_UNCHANGING_P (mem) = 1;
-      loop_info->store_mems 
+      loop_info->store_mems
        = gen_rtx_EXPR_LIST (VOIDmode, mem, loop_info->store_mems);
     }
 }
 \f
-/* LOOP->CONT_DOMINATOR is now the last label between the loop start
-   and the continue note that is a the destination of a (cond)jump after
-   the continue note.  If there is any (cond)jump between the loop start
-   and what we have so far as LOOP->CONT_DOMINATOR that has a
-   target between LOOP->CONT_DOMINATOR and the continue note, move
-   LOOP->CONT_DOMINATOR forward to that label; if a jump's
-   destination cannot be determined, clear LOOP->CONT_DOMINATOR.  */
+/* Invalidate all loops containing LABEL.  */
 
 static void
-verify_dominator (loop)
-     struct loop *loop;
+invalidate_loops_containing_label (label)
+     rtx label;
 {
-  rtx insn;
-
-  if (! loop->cont_dominator)
-    /* This can happen for an empty loop, e.g. in
-       gcc.c-torture/compile/920410-2.c  */
-    return;
-  if (loop->cont_dominator == const0_rtx)
-    {
-      loop->cont_dominator = 0;
-      return;
-    }
-  for (insn = loop->start; insn != loop->cont_dominator;
-       insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == JUMP_INSN
-         && GET_CODE (PATTERN (insn)) != RETURN)
-       {
-         rtx label = JUMP_LABEL (insn);
-         int label_luid;
-
-         /* If it is not a jump we can easily understand or for
-            which we do not have jump target information in the JUMP_LABEL
-            field (consider ADDR_VEC and ADDR_DIFF_VEC insns), then clear
-            LOOP->CONT_DOMINATOR.  */
-         if (! any_condjump_p (insn)
-             || label == NULL_RTX)
-           {
-             loop->cont_dominator = NULL_RTX;
-             return;
-           }
-
-         label_luid = INSN_LUID (label);
-         if (label_luid < INSN_LUID (loop->cont)
-             && (label_luid
-                 > INSN_LUID (loop->cont)))
-           loop->cont_dominator = 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.
@@ -2528,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;
@@ -2554,51 +2780,26 @@ find_and_verify_loops (f, loops)
              abort ();
 
            current_loop->end = insn;
-           verify_dominator (current_loop);
            current_loop = current_loop->outer;
            break;
 
          default:
            break;
          }
-      /* If for any loop, this is a jump insn between the NOTE_INSN_LOOP_CONT
-        and NOTE_INSN_LOOP_END notes, update loop->cont_dominator.  */
-      else if (GET_CODE (insn) == JUMP_INSN
-              && GET_CODE (PATTERN (insn)) != RETURN
-              && current_loop)
-       {
-         rtx label = JUMP_LABEL (insn);
-
-         if (! any_condjump_p (insn))
-           label = NULL_RTX;
 
-         loop = current_loop;
-         do
+      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)
            {
-             /* First see if we care about this loop.  */
-             if (loop->cont && loop->cont_dominator != const0_rtx)
-               {
-                 /* If the jump destination is not known, invalidate
-                    loop->cont_dominator.  */
-                 if (! label)
-                   loop->cont_dominator = const0_rtx;
-                 else
-                   /* Check if the destination is between loop start and
-                      cont.  */
-                   if ((INSN_LUID (label)
-                        < INSN_LUID (loop->cont))
-                       && (INSN_LUID (label)
-                           > INSN_LUID (loop->start))
-                       /* And if there is no later destination already
-                          recorded.  */
-                       && (! loop->cont_dominator
-                           || (INSN_LUID (label)
-                               > INSN_LUID (loop->cont_dominator))))
-                     loop->cont_dominator = label;
-               }
-             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));
            }
-         while (loop);
        }
 
       /* Note that this will mark the NOTE_INSN_LOOP_END note as being in the
@@ -2608,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.
@@ -2648,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)
@@ -2732,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
@@ -2774,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
@@ -2795,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.  */
@@ -2812,9 +3006,9 @@ find_and_verify_loops (f, loops)
                           off LABEL_OUTSIDE_LOOP_P bit.  */
                        if (JUMP_LABEL (insn))
                          {
-                           for (q = 0,
-                                  r = this_loop->exit_labels;
-                                r; q = r, r = LABEL_NEXTREF (r))
+                           for (q = 0, r = this_loop->exit_labels;
+                                r;
+                                q = r, r = LABEL_NEXTREF (r))
                              if (XEXP (r, 0) == JUMP_LABEL (insn))
                                {
                                  LABEL_OUTSIDE_LOOP_P (r) = 0;
@@ -2846,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
@@ -2856,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);
@@ -3050,7 +3244,7 @@ note_addr_stored (x, y, data)
   /* Count number of memory writes.
      This affects heuristics in strength_reduce.  */
   loop_info->num_mem_sets++;
-  
+
   /* BLKmode MEM means all memory is clobbered.  */
   if (GET_MODE (x) == BLKmode)
     {
@@ -3058,11 +3252,11 @@ note_addr_stored (x, y, data)
        loop_info->unknown_constant_address_altered = 1;
       else
        loop_info->unknown_address_altered = 1;
-      
+
       return;
     }
-  
-  loop_info->store_mems = gen_rtx_EXPR_LIST (VOIDmode, x, 
+
+  loop_info->store_mems = gen_rtx_EXPR_LIST (VOIDmode, x,
                                             loop_info->store_mems);
 }
 
@@ -3094,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
@@ -3109,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;
 
@@ -3140,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;
@@ -3155,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;
 
@@ -3163,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
@@ -3213,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));
@@ -3251,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;
 
@@ -3259,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);
@@ -3298,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);
 }
@@ -3320,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)
@@ -3346,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)
@@ -3368,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)
     {
@@ -3407,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)
-       bzero ((char *) last_set, 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
@@ -3523,102 +3664,743 @@ 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'.  */
-
-/* Communication with routines called via `note_stores'.  */
 
-static rtx note_insn;
+/* 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.  */
+};
 
-/* Dummy register to have non-zero DEST_REG for DEST_ADDR type givs.  */
+/* Data used by check_store function.  */
+struct check_store_data
+{
+  rtx mem_address;
+  int mem_write;
+};
 
-static rtx addr_placeholder;
+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));
 
-/* ??? Unfinished optimizations, and possible future optimizations,
-   for the strength reduction code.  */
+/* 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;
 
-/* ??? The interaction of biv elimination, and recognition of 'constant'
-   bivs, may cause problems.  */
+  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.
 
-/* ??? Add heuristics so that DEST_ADDR strength reduction does not cause
-   performance problems.
+   ??? Same trick with swapping operand is done at several other places.
+   It can be nice to develop some common way to handle this.  */
 
-   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.  */
+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;
 
-/* ??? Could try to optimize branches when it is known that a biv is always
-   positive.  */
+  if (x == y)
+    return 1;
+  if (code != GET_CODE (y))
+    return 0;
 
-/* ??? 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.  */
+  code = GET_CODE (x);
 
-/* ??? 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.
+  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.  */
 
-   NOT_EVERY_ITERATION if current insn is not executed at least once for every
-   loop iteration except for the last one.
+  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;
 
-   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;
-{
-  /* 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;
+       case 'i':
+         if (XINT (x, i) != XINT (y, i))
+           return 0;
+         break;
 
-  /* 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);
+       case 'E':
+         /* Two vectors must have the same length.  */
+         if (XVECLEN (x, i) != XVECLEN (y, i))
+           return 0;
 
-  /* Scan through loop to find all possible bivs.  */
+         /* 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;
 
-  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);
+       case 'e':
+         if (rtx_equal_for_prefetch_p (XEXP (x, i), XEXP (y, i)) == 0)
+           return 0;
+         break;
 
-      /* 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.  */
+       case 's':
+         if (strcmp (XSTR (x, i), XSTR (y, i)))
+           return 0;
+         break;
 
-      if (GET_CODE (p) == CODE_LABEL)
-       {
-         rtx insn = p;
+       case 'u':
+         /* These are just backpointers, so they don't matter.  */
+         break;
 
-         maybe_multiple = 0;
+       case '0':
+         break;
 
-         while (1)
-           {
-             insn = NEXT_INSN (insn);
-             if (insn == loop->scan_start)
-               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
+/* Remove constant addition value from the expression X (when present)
+   and return it.  */
+
+static HOST_WIDE_INT
+remove_constant_addition (x)
+     rtx *x;
+{
+  HOST_WIDE_INT addval = 0;
+  rtx exp = *x;
+
+  /* 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;
+{
+  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);
+
+  if (!HAVE_prefetch)
+    return;
+
+  /* Consider only loops w/o calls.  When a call is done, the loop is probably
+     slow enough to read the memory.  */
+  if (PREFETCH_NO_CALL && LOOP_INFO (loop)->has_call)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream, "Prefetch: ignoring loop: has call.\n");
+
+      return;
+    }
+
+  /* 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;
+    }
+
+  /* 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;
+
+      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)
+           {
+             if (loop_dump_stream)
+               {
+                 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)
@@ -3652,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;
 
@@ -3719,82 +4501,33 @@ for_each_insn_in_loop (loop, fncall)
     }
 }
 \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.  */
-
 static void
-strength_reduce (loop, insn_count, flags)
+loop_bivs_find (loop)
      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.  */
+  /* Temporary list pointers for traversing ivs->list.  */
   struct iv_class *bl, **backbl;
-  /* 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
-     and more registers are available.  */
-  /* ??? could set this to last value of threshold in move_movables */
-  int threshold = (loop_info->has_call ? 1 : 2) * (3 + n_non_fixed_regs);
-  /* Map of pseudo-register replacements.  */
-  rtx *reg_map = NULL;
-  int reg_map_size;
-  int call_seen;
-  rtx test;
-  rtx end_insert_before;
-  int n_extra_increment;
-  int unrolled_insn_copies = 0;
-  rtx loop_start = loop->start;
-  rtx loop_end = loop->end;
-  rtx loop_scan_start = loop->scan_start;
-  rtx test_reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
-
-  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);
+  ivs->list = 0;
 
   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.
+  /* 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->loop_iv_list, bl = *backbl; bl; bl = bl->next)
+  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: */
-         || VARRAY_INT (regs->n_times_set, bl->regno) != bl->biv_count
+         || 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, "Reg %d: biv discarded, %s\n",
+           fprintf (loop_dump_stream, "Biv %d: discarded, %s\n",
                     bl->regno,
                     (REG_IV_TYPE (ivs, bl->regno) != BASIC_INDUCT
                      ? "not induction variable"
@@ -3809,27 +4542,32 @@ strength_reduce (loop, insn_count, flags)
          backbl = &bl->next;
 
          if (loop_dump_stream)
-           fprintf (loop_dump_stream, "Reg %d: biv verified\n", bl->regno);
+           fprintf (loop_dump_stream, "Biv %d: verified\n", bl->regno);
        }
     }
+}
 
-  /* Exit if there are no bivs.  */
-  if (! ivs->loop_iv_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);
 
-      goto egress;
-    }
+/* 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))
+  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)
@@ -3843,12 +4581,12 @@ strength_reduce (loop, insn_count, flags)
         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)
+         && 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 = 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!  */
@@ -3862,11 +4600,22 @@ strength_reduce (loop, insn_count, flags)
            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.)  */
-  for (backbl = &ivs->loop_iv_list; (bl = *backbl); backbl = &bl->next)
+
+/* 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;
@@ -3886,409 +4635,588 @@ strength_reduce (loop, insn_count, flags)
 
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
-                "Biv %d initialized at insn %d: initial value ",
+                "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))
+         && 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)
            {
-             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");
-               }
+             print_simple_rtl (loop_dump_stream, src);
+             fputc ('\n', loop_dump_stream);
            }
        }
-      else
+      /* 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)
        {
-         struct iv_class *bl2 = 0;
-         rtx increment = NULL_RTX;
-
-         /* Biv initial value is not a simple move.  If it is the sum of
-            another biv and a constant, check if both bivs are incremented
-            in lockstep.  Then we are actually looking at a giv.
-            For simplicity, we only handle the case where there is but a
-            single increment, and the register is not used elsewhere.  */
-         if (bl->biv_count == 1
-             && bl->regno < max_reg_before_loop
-             && uid_luid[REGNO_LAST_UID (bl->regno)] < INSN_LUID (loop_end)
-             && GET_CODE (src) == PLUS
-             && GET_CODE (XEXP (src, 0)) == REG
-             && CONSTANT_P (XEXP (src, 1))
-             && ((increment = biv_total_increment (bl)) != NULL_RTX))
-           {
-             unsigned int regno = REGNO (XEXP (src, 0));
+         int auto_inc_opt = 0;
 
-             for (bl2 = ivs->loop_iv_list; bl2; bl2 = bl2->next)
-               if (bl2->regno == regno)
-                 break;
-           }
+         /* 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);
 
-         /* Now, can we transform this biv into a giv?  */
-         if (bl2
-             && bl2->biv_count == 1
-             && rtx_equal_p (increment, biv_total_increment (bl2))
-             /* init_insn is only set to insns that are before loop_start
-                without any intervening labels.  */
-             && ! reg_set_between_p (bl2->biv->src_reg,
-                                     PREV_INSN (bl->init_insn), loop_start)
-             /* The register from BL2 must be set before the register from
-                BL is set, or we must be able to move the latter set after
-                the former set.  Currently there can't be any labels
-                in-between when biv_total_increment returns nonzero both times
-                but we test it here in case some day some real cfg analysis
-                gets used to set always_computable.  */
-             && (loop_insn_first_p (bl2->biv->insn, bl->biv->insn)
-                 ? no_labels_between_p (bl2->biv->insn, bl->biv->insn)
-                 : (! reg_used_between_p (bl->biv->src_reg, bl->biv->insn,
-                                          bl2->biv->insn)
-                    && no_jumps_between_p (bl->biv->insn, bl2->biv->insn)))
-             && validate_change (bl->biv->insn,
-                                 &SET_SRC (single_set (bl->biv->insn)),
-                                 copy_rtx (src), 0))
+#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)
            {
-             rtx dominator = loop->cont_dominator;
-             rtx giv = bl->biv->src_reg;
-             rtx giv_insn = bl->biv->insn;
-             rtx after_giv = NEXT_INSN (giv_insn);
-
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream, "is giv of biv %d\n", bl2->regno);
-             /* Let this giv be discovered by the generic code.  */
-             REG_IV_TYPE (ivs, bl->regno) = UNKNOWN_INDUCT;
-             ivs->reg_biv_class[bl->regno] = (struct iv_class *) NULL_PTR;
-             /* We can get better optimization if we can move the giv setting
-                before the first giv use.  */
-             if (dominator
-                 && ! loop_insn_first_p (dominator, loop_scan_start)
-                 && ! reg_set_between_p (bl2->biv->src_reg, loop_start,
-                                         dominator)
-                 && ! reg_used_between_p (giv, loop_start, dominator)
-                 && ! reg_used_between_p (giv, giv_insn, loop_end))
+             /* 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)
                {
-                 rtx p;
-                 rtx next;
+                 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;
 
-                 for (next = NEXT_INSN (dominator);; next = NEXT_INSN (next))
-                   {
-                     if (GET_CODE (next) == JUMP_INSN
-                         || (INSN_P (next)
-                             && insn_dependent_p (giv_insn, next)))
-                       break;
 #ifdef HAVE_cc0
-                     if (! INSN_P (next) || ! sets_cc0_p (PATTERN (next)))
+             {
+               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
-                       dominator = next;
-                   }
-                 if (loop_dump_stream)
-                   fprintf (loop_dump_stream, "move after insn %d\n",
-                            INSN_UID (dominator));
-                 /* Avoid problems with luids by actually moving the insn
-                    and adjusting all luids in the range.  */
-                 reorder_insns (giv_insn, giv_insn, dominator);
-                 for (p = dominator; INSN_UID (p) >= max_uid_for_loop;)
-                   p = PREV_INSN (p);
-                 compute_luids (giv_insn, after_giv, INSN_LUID (p));
-                 /* If the only purpose of the init insn is to initialize
-                    this giv, delete it.  */
-                 if (single_set (bl->init_insn)
-                     && ! reg_used_between_p (giv, bl->init_insn, loop_start))
-                   delete_insn (bl->init_insn);
-               }
-             else if (! loop_insn_first_p (bl2->biv->insn, bl->biv->insn))
-               {
-                 rtx p = PREV_INSN (giv_insn);
-                 while (INSN_UID (p) >= max_uid_for_loop)
-                   p = PREV_INSN (p);
-                 reorder_insns (giv_insn, giv_insn, bl2->biv->insn);
-                 compute_luids (after_giv, NEXT_INSN (giv_insn),
-                                INSN_LUID (p));
-               }
-             /* Remove this biv from the chain.  */
-             *backbl = bl->next;
+
+             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);
            }
 
-         /* 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");
+         /* 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;
        }
     }
+}
 
-  /* If a biv is unconditionally incremented several times in a row, convert
-     all but the last increment into a giv.  */
 
-  /* Get an upper bound for the number of registers
-     we might have after all bivs have been processed.  */
-  ivs->first_increment_giv = max_reg_num ();
-  for (n_extra_increment = 0, bl = ivs->loop_iv_list; bl; bl = bl->next)
-    n_extra_increment += bl->biv_count - 1;
+static void
+loop_givs_rescan (loop, bl, reg_map)
+     struct loop *loop;
+     struct iv_class *bl;
+     rtx *reg_map;
+{
+  struct induction *v;
 
-  /* If the loop contains volatile memory references do not allow any
-     replacements to take place, since this could loose the volatile
-     markers.  */
-  if (n_extra_increment  && ! loop_info->has_volatile)
+  for (v = bl->giv; v; v = v->next_iv)
     {
-      unsigned int nregs = ivs->first_increment_giv + n_extra_increment;
+      if (v->same && v->same->ignore)
+       v->ignore = 1;
 
-      /* Reallocate ivs->reg_iv_type and ivs->reg_iv_info.  */
-      VARRAY_GROW (ivs->reg_iv_type, nregs);
-      VARRAY_GROW (ivs->reg_iv_info, nregs);
+      if (v->ignore)
+       continue;
 
-      for (bl = ivs->loop_iv_list; bl; bl = bl->next)
+      /* 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))
        {
-         struct induction **vp, *v, *next;
-         int biv_dead_after_loop = 0;
+         unsigned int align = REGNO_POINTER_ALIGN (REGNO (v->src_reg));
 
-         /* The biv increments lists are in reverse order.  Fix this
-             first.  */
-         for (v = bl->biv, bl->biv = 0; v; v = next)
-           {
-             next = v->next_iv;
-             v->next_iv = bl->biv;
-             bl->biv = v;
-           }
+         if (align == 0
+             || GET_CODE (v->add_val) != CONST_INT
+             || INTVAL (v->add_val) % (align / BITS_PER_UNIT) != 0)
+           align = 0;
 
-         /* We must guard against the case that an early exit between v->insn
-            and next->insn leaves the biv live after the loop, since that
-            would mean that we'd be missing an increment for the final
-            value.  The following test to set biv_dead_after_loop is like
-            the first part of the test to set bl->eliminable.
-            We don't check here if we can calculate the final value, since
-            this can't succeed if we already know that there is a jump
-            between v->insn and next->insn, yet next->always_executed is
-            set and next->maybe_multiple is cleared.  Such a combination
-            implies that the jump destination is outside the loop.
-            If we want to make this check more sophisticated, we should
-            check each branch between v->insn and next->insn individually
-            to see if the biv is dead at its destination.  */
-
-         if (uid_luid[REGNO_LAST_UID (bl->regno)] < INSN_LUID (loop_end)
-             && bl->init_insn
-             && INSN_UID (bl->init_insn) < max_uid_for_loop
-             && (uid_luid[REGNO_FIRST_UID (bl->regno)]
-                 >= INSN_LUID (bl->init_insn))
-#ifdef HAVE_decrement_and_branch_until_zero
-             && ! bl->nonneg
+         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
-             && ! reg_mentioned_p (bl->biv->dest_reg, SET_SRC (bl->init_set)))
-           biv_dead_after_loop = 1;
 
-         for (vp = &bl->biv, next = *vp; v = next, next = v->next_iv;)
-           {
-             HOST_WIDE_INT offset;
-             rtx set, add_val, old_reg, dest_reg, last_use_insn, note;
-             int old_regno, new_regno;
-             rtx next_loc_insn;
-
-             if (! v->always_executed
-                 || v->maybe_multiple
-                 || GET_CODE (v->add_val) != CONST_INT
-                 || ! next->always_executed
-                 || next->maybe_multiple
-                 || ! CONSTANT_P (next->add_val)
-                 || v->mult_val != const1_rtx
-                 || next->mult_val != const1_rtx
-                 || ! (biv_dead_after_loop
-                       || no_jumps_between_p (v->insn, next->insn)))
-               {
-                 vp = &v->next_iv;
-                 continue;
-               }
-             offset = INTVAL (v->add_val);
-             set = single_set (v->insn);
-             add_val = plus_constant (next->add_val, offset);
-             old_reg = v->dest_reg;
-             dest_reg = gen_reg_rtx (v->mode);
-
-             /* Unlike ivs->reg_iv_type / ivs->reg_iv_info, the other
-                three arrays have been allocated with some slop
-                space, so we may not actually need to reallocate
-                them.  If we do, the following if statement will be
-                executed just once in this loop.  */
-             if ((unsigned) max_reg_num () > regs->n_times_set->num_elements)
-               {
-                 /* Grow all the remaining 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);
-               }
+  return benefit;
+}
+
 
-             /* Some bivs are incremented with a multi-insn sequence.
-                The first insn contains the add.  */
-             next_loc_insn = next->insn;
-             while (NOTE_P (next_loc_insn)
-                    || ! loc_mentioned_in_p (next->location,
-                                             PATTERN (next_loc_insn)))
-               next_loc_insn = PREV_INSN (next_loc_insn);
+/* 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;
+    }
+}
 
-             if (next_loc_insn == v->insn)
-               abort ();
 
-             if (! validate_change (next_loc_insn, next->location, add_val, 0))
-               {
-                 vp = &v->next_iv;
-                 continue;
-               }
+/* Perform strength reduction and induction variable elimination.
 
-             /* Here we can try to eliminate the increment by combining
-                it into the uses.  */
+   Pseudo registers created during this function will be beyond the
+   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.  */
 
-             /* Set last_use_insn so that we can check against it.  */
+static void
+strength_reduce (loop, flags)
+     struct loop *loop;
+     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 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
+     and more registers are available.  */
+  /* ??? could set this to last value of threshold in move_movables */
+  int threshold = (loop_info->has_call ? 1 : 2) * (3 + n_non_fixed_regs);
+  /* Map of pseudo-register replacements.  */
+  rtx *reg_map = NULL;
+  int reg_map_size;
+  int unrolled_insn_copies = 0;
+  rtx test_reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
+  int insn_count = count_insns_in_loop (loop);
 
-             for (last_use_insn = v->insn, p = NEXT_INSN (v->insn);
-                  p != next_loc_insn;
-                  p = next_insn_in_loop (loop, p))
-               {
-                 if (!INSN_P (p))
-                   continue;
-                 if (reg_mentioned_p (old_reg, PATTERN (p)))
-                   {
-                     last_use_insn = p;
-                   }
-               }
+  addr_placeholder = gen_reg_rtx (Pmode);
 
-             /* If we can't get the LUIDs for the insns, we can't
-                calculate the lifetime.  This is likely from unrolling
-                of an inner loop, so there is little point in making this
-                a DEST_REG giv anyways.  */
-             if (INSN_UID (v->insn) >= max_uid_for_loop
-                 || INSN_UID (last_use_insn) >= max_uid_for_loop
-                 || ! validate_change (v->insn, &SET_DEST (set), dest_reg, 0))
-               {
-                 /* Change the increment at NEXT back to what it was.  */
-                 if (! validate_change (next_loc_insn, next->location,
-                     next->add_val, 0))
-                   abort ();
-                 vp = &v->next_iv;
-                 continue;
-               }
-             next->add_val = add_val;
-             v->dest_reg = dest_reg;
-             v->giv_type = DEST_REG;
-             v->location = &SET_SRC (set);
-             v->cant_derive = 0;
-             v->combined_with = 0;
-             v->maybe_dead = 0;
-             v->derive_adjustment = 0;
-             v->same = 0;
-             v->ignore = 0;
-             v->new_reg = 0;
-             v->final_value = 0;
-             v->same_insn = 0;
-             v->auto_inc_opt = 0;
-             v->unrolled = 0;
-             v->shared = 0;
-             v->derived_from = 0;
-             v->always_computable = 1;
-             v->always_executed = 1;
-             v->replaceable = 1;
-             v->no_const_addval = 0;
-
-             old_regno = REGNO (old_reg);
-             new_regno = REGNO (dest_reg);
-             VARRAY_INT (regs->set_in_loop, old_regno)--;
-             VARRAY_INT (regs->set_in_loop, new_regno) = 1;
-             VARRAY_INT (regs->n_times_set, old_regno)--;
-             VARRAY_INT (regs->n_times_set, new_regno) = 1;
-             VARRAY_CHAR (regs->may_not_optimize, new_regno) = 0;
-
-             REG_IV_TYPE (ivs, new_regno) = GENERAL_INDUCT;
-             REG_IV_INFO (ivs, new_regno) = v;
-
-             /* If next_insn has a REG_EQUAL note that mentiones OLD_REG,
-                it must be replaced.  */
-             note = find_reg_note (next->insn, REG_EQUAL, NULL_RTX);
-             if (note && reg_mentioned_p (old_reg, XEXP (note, 0)))
-               XEXP (note, 0) = copy_rtx (SET_SRC (single_set (next->insn)));
-
-             /* Remove the increment from the list of biv increments,
-                and record it as a giv.  */
-             *vp = next;
-             bl->biv_count--;
-             v->next_iv = bl->giv;
-             bl->giv = v;
-             bl->giv_count++;
-             v->benefit = rtx_cost (SET_SRC (set), SET);
-             bl->total_benefit += v->benefit;
-
-             /* Now replace the biv with DEST_REG in all insns between
-                the replaced increment and the next increment, and
-                remember the last insn that needed a replacement.  */
-             for (last_use_insn = v->insn, p = NEXT_INSN (v->insn);
-                  p != next_loc_insn;
-                  p = next_insn_in_loop (loop, p))
-               {
-                 rtx note;
+  ivs->n_regs = max_reg_before_loop;
+  ivs->regs = (struct iv *) xcalloc (ivs->n_regs, sizeof (struct iv));
 
-                 if (! INSN_P (p))
-                   continue;
-                 if (reg_mentioned_p (old_reg, PATTERN (p)))
-                   {
-                     last_use_insn = p;
-                     if (! validate_replace_rtx (old_reg, dest_reg, p))
-                       abort ();
-                   }
-                 for (note = REG_NOTES (p); note; note = XEXP (note, 1))
-                   {
-                     if (GET_CODE (note) == EXPR_LIST)
-                       XEXP (note, 0)
-                         = replace_rtx (XEXP (note, 0), old_reg, dest_reg);
-                   }
-               }
+  /* Find all BIVs in loop.  */
+  loop_bivs_find (loop);
 
-             v->last_use = last_use_insn;
-             v->lifetime = INSN_LUID (last_use_insn) - INSN_LUID (v->insn);
-             /* If the lifetime is zero, it means that this register is really
-                a dead store.  So mark this as a giv that can be ignored.
-                This will not prevent the biv from being eliminated.  */
-             if (v->lifetime == 0)
-               v->ignore = 1;
+  /* Exit if there are no bivs.  */
+  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, 0);
 
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream,
-                        "Increment %d of biv %d converted to giv %d.\n\n",
-                        INSN_UID (v->insn), old_regno, new_regno);
-           }
-       }
+      loop_ivs_free (loop);
+      return;
     }
-  ivs->last_increment_giv = max_reg_num () - 1;
 
-  /* Search the loop for general induction variables.  */
+  /* Determine how BIVS are initialized by looking through pre-header
+     extended basic block.  */
+  loop_bivs_init_find (loop);
 
-  for_each_insn_in_loop (loop, check_insn_for_givs);
+  /* Look at the each biv and see if we can say anything better about its
+     initial value from any initializing insns set up above.  */
+  loop_bivs_check (loop);
+
+  /* Search the loop for general induction variables.  */
+  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
@@ -4298,149 +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;
-      unsigned int nregs;
 
       /* 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 ((uid_luid[REGNO_LAST_UID (bl->regno)] < INSN_LUID (loop_end)
-          && bl->init_insn
-          && INSN_UID (bl->init_insn) < max_uid_for_loop
-          && uid_luid[REGNO_FIRST_UID (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
@@ -4448,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,
@@ -4457,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
            {
@@ -4473,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;
                  }
            }
@@ -4483,210 +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->last_use)
-           {
-             struct induction *v1;
-
-             for (v1 = bl->giv; v1; v1 = v1->next_iv)
-               if (v->last_use == v1->insn)
-                 v->maybe_dead = 1;
-           }
-         else 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;
-           }
-       }
-
-      /* Now that we know which givs will be reduced, try to rearrange the
-         combinations to reduce register pressure.
-         recombine_givs calls find_life_end, which needs ivs->reg_iv_type and
-        ivs->reg_iv_info to be valid for all pseudos.  We do the necessary
-        reallocation here since it allows to check if there are still
-        more bivs to process.  */
-      nregs = max_reg_num ();
-      if (nregs > ivs->reg_iv_type->num_elements)
-       {
-         /* If there are still more bivs to process, allocate some slack
-            space so that we're not constantly reallocating these arrays.  */
-         if (bl->next)
-           nregs += nregs / 4;
-         /* Reallocate ivs->reg_iv_type and ivs->reg_iv_info.  */
-         VARRAY_GROW (ivs->reg_iv_type, nregs);
-         VARRAY_GROW (ivs->reg_iv_info, nregs);
-       }
-      recombine_givs (loop, bl, flags & LOOP_UNROLL);
+      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);
-
-             if (v->derived_from)
-               {
-                 struct induction *d = v->derived_from;
-
-                 /* In case d->dest_reg is not replaceable, we have
-                    to replace it in v->insn now.  */
-                 if (! d->new_reg)
-                   d->new_reg = gen_reg_rtx (d->mode);
-                 PATTERN (v->insn)
-                   = replace_rtx (PATTERN (v->insn), d->dest_reg, d->new_reg);
-                 PATTERN (v->insn)
-                   = replace_rtx (PATTERN (v->insn), v->dest_reg, v->new_reg);
-                 /* For each place where the biv is incremented, add an
-                    insn to set the new, reduced reg for the giv.
-                    We used to do this only for biv_count != 1, but
-                    this fails when there is a giv after a single biv
-                    increment, e.g. when the last giv was expressed as
-                    pre-decrement.  */
-                 for (tv = bl->biv; tv; tv = tv->next_iv)
-                   {
-                     /* We always emit reduced giv increments before the
-                        biv increment when bl->biv_count != 1.  So by
-                        emitting the add insns for derived givs after the
-                        biv increment, they pick up the updated value of
-                        the reduced giv.
-                        If the reduced giv is processed with
-                        auto_inc_opt == 1, then it is incremented earlier
-                        than the biv, hence we'll still pick up the right
-                        value.
-                        If it's processed with auto_inc_opt == -1,
-                        that implies that the biv increment is before the
-                        first reduced giv's use.  The derived giv's lifetime
-                        is after the reduced giv's lifetime, hence in this
-                        case, the biv increment doesn't matter.  */
-                     emit_insn_after (copy_rtx (PATTERN (v->insn)), tv->insn);
-                   }
-                 continue;
-               }
-
-#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.
@@ -4694,102 +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);
-
-         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.  */
@@ -4799,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
@@ -4827,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,
@@ -4842,46 +5371,26 @@ strength_reduce (loop, insn_count, flags)
             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 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
+         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)
       {
@@ -4922,22 +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);
+  loop_ivs_free (loop);
   if (reg_map)
     free (reg_map);
 }
@@ -4975,13 +5494,13 @@ check_insn_for_bivs (loop, p, not_every_iteration, maybe_multiple)
                 Create and initialize an induction structure for it.  */
 
              struct induction *v
-               = (struct induction *) oballoc (sizeof (struct induction));
+               = (struct induction *) xmalloc (sizeof (struct induction));
 
              record_biv (loop, v, p, dest_reg, inc_val, mult_val, location,
                          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;
        }
     }
@@ -5005,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;
@@ -5034,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,
@@ -5042,31 +5561,27 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
                                             &last_consec_insn))))
        {
          struct induction *v
-           = (struct induction *) oballoc (sizeof (struct induction));
+           = (struct induction *) xmalloc (sizeof (struct induction));
 
          /* If this is a library call, increase benefit.  */
          if (find_reg_note (p, REG_RETVAL, NULL_RTX))
            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.  */
@@ -5119,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)
@@ -5128,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;
@@ -5163,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,
@@ -5171,13 +5686,13 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
          {
            /* Found one; record it.  */
            struct induction *v
-             = (struct induction *) oballoc (sizeof (struct induction));
+             = (struct induction *) xmalloc (sizeof (struct induction));
 
            record_giv (loop, v, insn, src_reg, addr_placeholder, mult_val,
                        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;
@@ -5236,22 +5751,23 @@ 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.  */
 
-      bl = (struct iv_class *) oballoc (sizeof (struct iv_class));
+      bl = (struct iv_class *) xmalloc (sizeof (struct iv_class));
 
       bl->regno = REGNO (dest_reg);
       bl->biv = 0;
@@ -5261,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;
@@ -5271,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.  */
@@ -5287,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.
@@ -5339,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;
@@ -5350,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;
@@ -5366,8 +5881,6 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
   v->auto_inc_opt = 0;
   v->unrolled = 0;
   v->shared = 0;
-  v->derived_from = 0;
-  v->last_use = 0;
 
   /* The v->always_computable field is used in update_giv_derive, to
      determine whether a giv can be used to derive another giv.  For a
@@ -5393,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 = (uid_luid[REGNO_LAST_UID (REGNO (dest_reg))]
-                    - uid_luid[REGNO_FIRST_UID (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
@@ -5408,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;
@@ -5424,22 +5936,25 @@ 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)
          /* Previous line always fails if INSN was moved by loop opt.  */
-         && uid_luid[REGNO_LAST_UID (REGNO (dest_reg))]
+         && REGNO_LAST_LUID (REGNO (dest_reg))
          < INSN_LUID (loop->end)
          && (! not_every_iteration
              || last_use_this_basic_block (dest_reg, insn)))
@@ -5459,13 +5974,14 @@ 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
-                 || ((uid_luid[INSN_UID (b->insn)]
-                      >= uid_luid[REGNO_FIRST_UID (REGNO (dest_reg))])
-                     && (uid_luid[INSN_UID (b->insn)]
-                         <= uid_luid[REGNO_LAST_UID (REGNO (dest_reg))])))
+                 || ((INSN_LUID (b->insn)
+                      >= REGNO_FIRST_LUID (REGNO (dest_reg)))
+                     && (INSN_LUID (b->insn)
+                         <= REGNO_LAST_LUID (REGNO (dest_reg)))))
                {
                  v->replaceable = 0;
                  v->not_replaceable = 1;
@@ -5505,84 +6021,22 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
       v->no_const_addval = 0;
     if (GET_CODE (tem) == PLUS)
       {
-       while (1)
-         {
-           if (GET_CODE (XEXP (tem, 0)) == PLUS)
-             tem = XEXP (tem, 0);
-           else if (GET_CODE (XEXP (tem, 1)) == PLUS)
-             tem = XEXP (tem, 1);
-           else
-             break;
-         }
-       if (CONSTANT_P (XEXP (tem, 1)))
-         v->no_const_addval = 0;
-      }
-  }
-
-  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);
-       }
-    }
+       while (1)
+         {
+           if (GET_CODE (XEXP (tem, 0)) == PLUS)
+             tem = XEXP (tem, 0);
+           else if (GET_CODE (XEXP (tem, 1)) == PLUS)
+             tem = XEXP (tem, 1);
+           else
+             break;
+         }
+       if (CONSTANT_P (XEXP (tem, 1)))
+         v->no_const_addval = 0;
+      }
+  }
 
   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
@@ -5596,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.  */
 
@@ -5614,6 +6064,7 @@ check_final_value (loop, v)
         or all uses follow that insn in the same basic block),
      - its final value can be calculated (this condition is different
        than the one above in record_giv)
+     - it's not used before the it's set
      - no assignments to the biv occur during the giv's lifetime.  */
 
 #if 0
@@ -5623,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;
+      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
@@ -5655,7 +6108,10 @@ check_final_value (loop, v)
        {
          p = NEXT_INSN (p);
          if (p == loop->end)
-           p = NEXT_INSN (loop->start);
+           {
+             before_giv_insn = 1;
+             p = NEXT_INSN (loop->start);
+           }
          if (p == v->insn)
            break;
 
@@ -5670,10 +6126,10 @@ check_final_value (loop, v)
              if (! biv_increment_seen
                  && reg_set_p (v->src_reg, PATTERN (p)))
                biv_increment_seen = 1;
-               
+
              if (reg_mentioned_p (v->dest_reg, PATTERN (p)))
                {
-                 if (biv_increment_seen)
+                 if (biv_increment_seen || before_giv_insn)
                    {
                      v->replaceable = 0;
                      v->not_replaceable = 1;
@@ -5777,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)
@@ -5875,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;
@@ -5883,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;
 
@@ -5919,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
@@ -5939,6 +6395,7 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
       insn = p;
       while (1)
        {
+         rtx dest;
          do
            {
              insn = PREV_INSN (insn);
@@ -5951,26 +6408,31 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
          set = single_set (insn);
          if (set == 0)
            break;
-
-         if ((SET_DEST (set) == x
-              || (GET_CODE (SET_DEST (set)) == SUBREG
-                  && (GET_MODE_SIZE (GET_MODE (SET_DEST (set)))
-                      <= UNITS_PER_WORD)
-                  && (GET_MODE_CLASS (GET_MODE (SET_DEST (set)))
-                      == MODE_INT)
-                  && SUBREG_REG (SET_DEST (set)) == x))
-             && basic_induction_var (loop, SET_SRC (set),
-                                     (GET_MODE (SET_SRC (set)) == VOIDmode
-                                      ? GET_MODE (x)
-                                      : GET_MODE (SET_SRC (set))),
-                                     dest_reg, insn,
-                                     inc_val, mult_val, location))
-           return 1;
+         dest = SET_DEST (set);
+         if (dest == x
+             || (GET_CODE (dest) == SUBREG
+                 && (GET_MODE_SIZE (GET_MODE (dest)) <= UNITS_PER_WORD)
+                 && (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT)
+                 && SUBREG_REG (dest) == x))
+           return basic_induction_var (loop, SET_SRC (set),
+                                       (GET_MODE (SET_SRC (set)) == VOIDmode
+                                        ? GET_MODE (x)
+                                        : GET_MODE (SET_SRC (set))),
+                                       dest_reg, insn,
+                                       inc_val, mult_val, location);
+
+         while (GET_CODE (dest) == SIGN_EXTRACT
+                || GET_CODE (dest) == ZERO_EXTRACT
+                || GET_CODE (dest) == SUBREG
+                || GET_CODE (dest) == STRICT_LOW_PART)
+           dest = XEXP (dest, 0);
+         if (dest == x)
+           break;
        }
-      /* ... fall through ...  */
+      /* 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:
@@ -5981,11 +6443,12 @@ 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);
          *mult_val = const0_rtx;
@@ -5995,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);
 
@@ -6055,23 +6521,16 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   rtx orig_x = x;
-  char *storage;
 
   /* If this is an invariant, forget it, it isn't a giv.  */
   if (loop_invariant_p (loop, x) == 1)
     return 0;
 
-  /* See if the expression could be a giv and get its form.
-     Mark our place on the obstack in case we don't find a giv.  */
-  storage = (char *) oballoc (0);
   *pbenefit = 0;
   *ext_val = NULL_RTX;
   x = simplify_giv_expr (loop, x, ext_val, pbenefit);
   if (x == 0)
-    {
-      obfree (storage);
-      return 0;
-    }
+    return 0;
 
   switch (GET_CODE (x))
     {
@@ -6080,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;
@@ -6139,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.
 
@@ -6152,15 +6611,13 @@ 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.  */
 
 static rtx sge_plus PARAMS ((enum machine_mode, rtx, rtx));
 static rtx sge_plus_constant PARAMS ((rtx, rtx));
-static int cmp_combine_givs_stats PARAMS ((const PTR, const PTR));
-static int cmp_recombine_givs_stats PARAMS ((const PTR, const PTR));
 
 static rtx
 simplify_giv_expr (loop, x, ext_val, benefit)
@@ -6207,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)
@@ -6258,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)
@@ -6341,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.  */
@@ -6420,7 +6877,7 @@ simplify_giv_expr (loop, x, ext_val, benefit)
     case ZERO_EXTEND:
     case TRUNCATE:
       /* Conditionally recognize extensions of simple IVs.  After we've
-        computed loop traversal counts and verified the range of the 
+        computed loop traversal counts and verified the range of the
         source IV, we'll reevaluate this as a GIV.  */
       if (*ext_val == NULL_RTX)
        {
@@ -6433,7 +6890,7 @@ simplify_giv_expr (loop, x, ext_val, benefit)
        }
       goto do_default;
 
-  case REG:
+    case REG:
       /* If this is a new register, we can't deal with it.  */
       if (REGNO (x) >= max_reg_before_loop)
        return 0;
@@ -6458,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;
            }
@@ -6475,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;
@@ -6494,8 +6951,9 @@ simplify_giv_expr (loop, x, ext_val, benefit)
          if (loop_invariant_p (loop, x) == 1)
            {
              struct movable *m;
+             struct loop_movables *movables = LOOP_MOVABLES (loop);
 
-             for (m = the_movables.head; m; m = m->next)
+             for (m = movables->head; m; m = m->next)
                if (rtx_equal_p (x, m->set_dest))
                  {
                    /* Ok, we found a match.  Substitute and simplify.  */
@@ -6506,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.  */
@@ -6514,7 +6972,11 @@ simplify_giv_expr (loop, x, ext_val, benefit)
                      {
                        int i = m->consec;
                        tem = m->insn;
-                       do { tem = NEXT_INSN (tem); } while (--i > 0);
+                       do
+                         {
+                           tem = NEXT_INSN (tem);
+                         }
+                       while (--i > 0);
 
                        tem = find_reg_note (tem, REG_EQUAL, NULL_RTX);
                        if (tem)
@@ -6544,9 +7006,9 @@ simplify_giv_expr (loop, x, ext_val, benefit)
                              return tem;
                          }
                        else if (GET_CODE (tem) == CONST
-                           && GET_CODE (XEXP (tem, 0)) == PLUS
-                           && GET_CODE (XEXP (XEXP (tem, 0), 0)) == SYMBOL_REF
-                           && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)
+                                && GET_CODE (XEXP (tem, 0)) == PLUS
+                                && GET_CODE (XEXP (XEXP (tem, 0), 0)) == SYMBOL_REF
+                                && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)
                          {
                            tem = simplify_giv_expr (loop, XEXP (tem, 0),
                                                     ext_val, benefit);
@@ -6680,20 +7142,24 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
      general_induction_var below, so we can allocate it on our stack.
      If this is a giv, our caller will replace the induct var entry with
      a new induction structure.  */
-  struct induction *v
-    = (struct induction *) alloca (sizeof (struct induction));
+  struct induction *v;
+
+  if (REG_IV_TYPE (ivs, REGNO (dest_reg)) != UNKNOWN_INDUCT)
+    return 0;
+
+  v = (struct induction *) alloca (sizeof (struct induction));
   v->src_reg = src_reg;
   v->mult_val = *mult_val;
   v->add_val = *add_val;
   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)
     {
@@ -6742,6 +7208,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
        }
     }
 
+  REG_IV_TYPE (ivs, REGNO (dest_reg)) = UNKNOWN_INDUCT;
   *last_consec_insn = p;
   return v->benefit;
 }
@@ -6751,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.
 
@@ -6809,7 +7276,7 @@ express_from_1 (a, b, mult)
        a = ra, b = ob;
       else
        {
-          /* Indicates an extra register in B.  Strip one level from B and
+         /* Indicates an extra register in B.  Strip one level from B and
             recurse, hoping B was the higher order expression.  */
          ob = express_from_1 (a, ob, mult);
          if (ob == NULL_RTX)
@@ -6842,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)
     {
@@ -6947,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;
@@ -6974,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;
 
@@ -7013,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
@@ -7029,13 +7487,13 @@ check_ext_dependant_givs (bl, loop_info)
       info_ok = 1;
       start_val = INTVAL (bl->initial_value);
       u_start_val = start_val;
-          
+
       neg_incr = 0, abs_incr = INTVAL (incr);
       if (INTVAL (incr) < 0)
        neg_incr = 1, abs_incr = -abs_incr;
       total_incr = abs_incr * loop_info->n_iterations;
 
-      /* Check for host arithmatic overflow.  */
+      /* Check for host arithmetic overflow.  */
       if (total_incr / loop_info->n_iterations == abs_incr)
        {
          unsigned HOST_WIDE_INT u_max;
@@ -7045,10 +7503,10 @@ check_ext_dependant_givs (bl, loop_info)
          s_end_val = u_end_val;
          u_max = GET_MODE_MASK (biv_mode);
          s_max = u_max >> 1;
-                 
+
          /* Check zero extension of biv ok.  */
          if (start_val >= 0
-             /* Check for host arithmatic overflow.  */
+             /* Check for host arithmetic overflow.  */
              && (neg_incr
                  ? u_end_val < u_start_val
                  : u_end_val > u_start_val)
@@ -7059,14 +7517,14 @@ check_ext_dependant_givs (bl, loop_info)
            {
              ze_ok = 1;
            }
-                 
+
          /* Check sign extension of biv ok.  */
          /* ??? While it is true that overflow with signed and pointer
             arithmetic is undefined, I fear too many programmers don't
             keep this fact in mind -- myself included on occasion.
             So leave alone with the signed overflow optimizations.  */
          if (start_val >= -s_max - 1
-             /* Check for host arithmatic overflow.  */
+             /* Check for host arithmetic overflow.  */
              && (neg_incr
                  ? s_end_val < start_val
                  : s_end_val > start_val)
@@ -7082,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)
@@ -7099,12 +7557,12 @@ check_ext_dependant_givs (bl, loop_info)
          case TRUNCATE:
            /* We don't know whether this value is being used as either
               signed or unsigned, so to safely truncate we must satisfy
-              both.  The initial check here verifies the BIV itself; 
+              both.  The initial check here verifies the BIV itself;
               once that is successful we may check its range wrt the
               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,
@@ -7123,9 +7581,9 @@ 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",
-                       INSN_UID (v->insn), bl->regno);
+               fprintf (loop_dump_stream,
+                        "Verified ext dependent giv at %d of reg %d\n",
+                        INSN_UID (v->insn), bl->regno);
              }
          }
        else
@@ -7146,11 +7604,12 @@ check_ext_dependant_givs (bl, loop_info)
                      why = "biv iteration info incomplete";
                  }
 
-               fprintf(loop_dump_stream,
-                       "Failed ext dependant giv at %d, %s\n",
-                       INSN_UID (v->insn), why);
+               fprintf (loop_dump_stream,
+                        "Failed ext dependent giv at %d, %s\n",
+                        INSN_UID (v->insn), why);
              }
            v->ignore = 1;
+           bl->all_reduced = 0;
          }
       }
 }
@@ -7162,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)
@@ -7250,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;
 
@@ -7314,544 +7772,119 @@ restart:
              int l;
 
              g2->new_reg = can_combine[i * giv_count + j];
-             g2->same = g1;
-             g1->combined_with++;
-             g1->lifetime += g2->lifetime;
-
-             g1_add_benefit += g2->benefit;
-
-             /* ??? 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 (! g2->replaceable && REG_USERVAR_P (g2->dest_reg))
-               g1_add_benefit -= copy_cost;
-
-             /* To help optimize the next set of combinations, remove
-                this giv from the benefits of other potential mates.  */
-             for (l = 0; l < giv_count; ++l)
-               {
-                 int m = stats[l].giv_number;
-                 if (can_combine[m * giv_count + j])
-                   stats[l].total_benefit -= g2->benefit + extra_benefit;
-               }
-
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream,
-                        "giv at %d combined with giv at %d; new benefit %d + %d, lifetime %d\n",
-                        INSN_UID (g2->insn), INSN_UID (g1->insn),
-                        g1->benefit, g1_add_benefit, g1->lifetime);
-           }
-       }
-
-      /* To help optimize the next set of combinations, remove
-        this giv from the benefits of other potential mates.  */
-      if (g1->combined_with)
-       {
-         for (j = 0; j < giv_count; ++j)
-           {
-             int m = stats[j].giv_number;
-             if (can_combine[m * giv_count + i])
-               stats[j].total_benefit -= g1->benefit + extra_benefit;
-           }
-
-         g1->benefit += g1_add_benefit;
-
-         /* We've finished with this giv, and everything it touched.
-            Restart the combination so that proper weights for the
-            rest of the givs are properly taken into account.  */
-         /* ??? Ideally we would compact the arrays at this point, so
-            as to not cover old ground.  But sanely compacting
-            can_combine is tricky.  */
-         goto restart;
-       }
-    }
-
-  /* Clean up.  */
-  free (stats);
-  free (can_combine);
-}
-\f
-struct recombine_givs_stats
-{
-  int giv_number;
-  int start_luid, end_luid;
-};
-
-/* Used below as comparison function for qsort.  We want a ascending luid
-   when scanning the array starting at the end, thus the arguments are
-   used in reverse.  */
-static int
-cmp_recombine_givs_stats (xp, yp)
-     const PTR xp;
-     const PTR yp;
-{
-  const struct recombine_givs_stats * const x =
-    (const struct recombine_givs_stats *) xp;
-  const struct recombine_givs_stats * const y =
-    (const struct recombine_givs_stats *) yp;
-  int d;
-  d = y->start_luid - x->start_luid;
-  /* Stabilize the sort.  */
-  if (!d)
-    d = y->giv_number - x->giv_number;
-  return d;
-}
-
-/* Scan X, which is a part of INSN, for the end of life of a giv.  Also
-   look for the start of life of a giv where the start has not been seen
-   yet to unlock the search for the end of its life.
-   Only consider givs that belong to BIV.
-   Return the total number of lifetime ends that have been found.  */
-static int
-find_life_end (loop, x, stats, insn, biv)
-     const struct loop *loop;
-     rtx x, insn, biv;
-     struct recombine_givs_stats *stats;
-{
-  struct loop_ivs *ivs = LOOP_IVS (loop);
-  enum rtx_code code;
-  const char *fmt;
-  int i, j;
-  int retval;
-
-  code = GET_CODE (x);
-  switch (code)
-    {
-    case SET:
-      {
-       rtx reg = SET_DEST (x);
-       if (GET_CODE (reg) == REG)
-         {
-           int regno = REGNO (reg);
-           struct induction *v = REG_IV_INFO (ivs, regno);
-
-           if (REG_IV_TYPE (ivs, regno) == GENERAL_INDUCT
-               && ! v->ignore
-               && v->src_reg == biv
-               && stats[v->ix].end_luid <= 0)
-             {
-               /* If we see a 0 here for end_luid, it means that we have
-                  scanned the entire loop without finding any use at all.
-                  We must not predicate this code on a start_luid match
-                  since that would make the test fail for givs that have
-                  been hoisted out of inner loops.  */
-               if (stats[v->ix].end_luid == 0)
-                 {
-                   stats[v->ix].end_luid = stats[v->ix].start_luid;
-                   return 1 + find_life_end (loop, SET_SRC (x), stats,
-                                             insn, biv);
-                 }
-               else if (stats[v->ix].start_luid == INSN_LUID (insn))
-                 stats[v->ix].end_luid = 0;
-             }
-           return find_life_end (loop, SET_SRC (x), stats, insn, biv);
-         }
-       break;
-      }
-    case REG:
-      {
-       int regno = REGNO (x);
-       struct induction *v = REG_IV_INFO (ivs, regno);
-
-       if (REG_IV_TYPE (ivs, regno) == GENERAL_INDUCT
-           && ! v->ignore
-           && v->src_reg == biv
-           && stats[v->ix].end_luid == 0)
-         {
-           while (INSN_UID (insn) >= max_uid_for_loop)
-             insn = NEXT_INSN (insn);
-           stats[v->ix].end_luid = INSN_LUID (insn);
-           return 1;
-         }
-       return 0;
-      }
-    case LABEL_REF:
-    case CONST_DOUBLE:
-    case CONST_INT:
-    case CONST:
-      return 0;
-    default:
-      break;
-    }
-  fmt = GET_RTX_FORMAT (code);
-  retval = 0;
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    {
-      if (fmt[i] == 'e')
-       retval += find_life_end (loop, XEXP (x, i), stats, insn, biv);
-
-      else if (fmt[i] == 'E')
-       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-         retval += find_life_end (loop, XVECEXP (x, i, j), stats, insn, biv);
-    }
-  return retval;
-}
-
-/* For each giv that has been combined with another, look if
-   we can combine it with the most recently used one instead.
-   This tends to shorten giv lifetimes, and helps the next step:
-   try to derive givs from other givs.  */
-static void
-recombine_givs (loop, bl, unroll_p)
-     const struct loop *loop;
-     struct iv_class *bl;
-     int unroll_p;
-{
-  struct loop_regs *regs = LOOP_REGS (loop);
-  struct induction *v, **giv_array, *last_giv;
-  struct recombine_givs_stats *stats;
-  int giv_count;
-  int i, rescan;
-  int ends_need_computing;
-
-  for (giv_count = 0, v = bl->giv; v; v = v->next_iv)
-    {
-      if (! v->ignore)
-       giv_count++;
-    }
-  giv_array
-    = (struct induction **) xmalloc (giv_count * sizeof (struct induction *));
-  stats = (struct recombine_givs_stats *) xmalloc (giv_count * sizeof *stats);
-
-  /* Initialize stats and set up the ix field for each giv in stats to name
-     the corresponding index into stats.  */
-  for (i = 0, v = bl->giv; v; v = v->next_iv)
-    {
-      rtx p;
-
-      if (v->ignore)
-       continue;
-      giv_array[i] = v;
-      stats[i].giv_number = i;
-      /* If this giv has been hoisted out of an inner loop, use the luid of
-        the previous insn.  */
-      for (p = v->insn; INSN_UID (p) >= max_uid_for_loop; )
-       p = PREV_INSN (p);
-      stats[i].start_luid = INSN_LUID (p);
-      i++;
-    }
-
-  qsort (stats, giv_count, sizeof (*stats), cmp_recombine_givs_stats);
-
-  /* Set up the ix field for each giv in stats to name
-     the corresponding index into stats, and
-     do the actual most-recently-used recombination.  */
-  for (last_giv = 0, i = giv_count - 1; i >= 0; i--)
-    {
-      v = giv_array[stats[i].giv_number];
-      v->ix = i;
-      if (v->same)
-       {
-         struct induction *old_same = v->same;
-         rtx new_combine;
-
-         /* combine_givs_p actually says if we can make this transformation.
-            The other tests are here only to avoid keeping a giv alive
-            that could otherwise be eliminated.  */
-         if (last_giv
-             && ((old_same->maybe_dead && ! old_same->combined_with)
-                 || ! last_giv->maybe_dead
-                 || last_giv->combined_with)
-             && (new_combine = combine_givs_p (last_giv, v)))
-           {
-             old_same->combined_with--;
-             v->new_reg = new_combine;
-             v->same = last_giv;
-             last_giv->combined_with++;
-             /* No need to update lifetimes / benefits here since we have
-                already decided what to reduce.  */
-
-             if (loop_dump_stream)
-               {
-                 fprintf (loop_dump_stream,
-                          "giv at %d recombined with giv at %d as ",
-                          INSN_UID (v->insn), INSN_UID (last_giv->insn));
-                 print_rtl (loop_dump_stream, v->new_reg);
-                 putc ('\n', loop_dump_stream);
-               }
-             continue;
-           }
-         v = v->same;
-       }
-      else if (v->giv_type != DEST_REG)
-       continue;
-      if (! last_giv
-         || (last_giv->maybe_dead && ! last_giv->combined_with)
-         || ! v->maybe_dead
-         || v->combined_with)
-       last_giv = v;
-    }
-
-  ends_need_computing = 0;
-  /* For each DEST_REG giv, compute lifetime starts, and try to compute
-     lifetime ends from regscan info.  */
-  for (i = giv_count - 1; i >= 0; i--)
-    {
-      v = giv_array[stats[i].giv_number];
-      if (v->ignore)
-       continue;
-      if (v->giv_type == DEST_ADDR)
-       {
-         /* Loop unrolling of an inner loop can even create new DEST_REG
-            givs.  */
-         rtx p;
-         for (p = v->insn; INSN_UID (p) >= max_uid_for_loop;)
-           p = PREV_INSN (p);
-         stats[i].start_luid = stats[i].end_luid = INSN_LUID (p);
-         if (p != v->insn)
-           stats[i].end_luid++;
-       }
-      else /* v->giv_type == DEST_REG */
-       {
-         if (v->last_use)
-           {
-             stats[i].start_luid = INSN_LUID (v->insn);
-             stats[i].end_luid = INSN_LUID (v->last_use);
-           }
-         else if (INSN_UID (v->insn) >= max_uid_for_loop)
-           {
-             rtx p;
-             /* This insn has been created by loop optimization on an inner
-                loop.  We don't have a proper start_luid that will match
-                when we see the first set.  But we do know that there will
-                be no use before the set, so we can set end_luid to 0 so that
-                we'll start looking for the last use right away.  */
-             for (p = PREV_INSN (v->insn); INSN_UID (p) >= max_uid_for_loop; )
-               p = PREV_INSN (p);
-             stats[i].start_luid = INSN_LUID (p);
-             stats[i].end_luid = 0;
-             ends_need_computing++;
-           }
-         else
-           {
-             int regno = REGNO (v->dest_reg);
-             int count = VARRAY_INT (regs->n_times_set, regno) - 1;
-             rtx p = v->insn;
-
-             /* Find the first insn that sets the giv, so that we can verify
-                if this giv's lifetime wraps around the loop.  We also need
-                the luid of the first setting insn in order to detect the
-                last use properly.  */
-             while (count)
-               {
-                 p = prev_nonnote_insn (p);
-                 if (reg_set_p (v->dest_reg, p))
-                   count--;
-               }
-
-             stats[i].start_luid = INSN_LUID (p);
-             if (stats[i].start_luid > uid_luid[REGNO_FIRST_UID (regno)])
-               {
-                 stats[i].end_luid = -1;
-                 ends_need_computing++;
-               }
-             else
-               {
-                 stats[i].end_luid = uid_luid[REGNO_LAST_UID (regno)];
-                 if (stats[i].end_luid > INSN_LUID (loop->end))
-                   {
-                     stats[i].end_luid = -1;
-                     ends_need_computing++;
-                   }
-               }
-           }
-       }
-    }
-
-  /* If the regscan information was unconclusive for one or more DEST_REG
-     givs, scan the all insn in the loop to find out lifetime ends.  */
-  if (ends_need_computing)
-    {
-      rtx biv = bl->biv->src_reg;
-      rtx p = loop->end;
-
-      do
-       {
-         if (p == loop->start)
-           p = loop->end;
-         p = PREV_INSN (p);
-         if (! INSN_P (p))
-           continue;
-         ends_need_computing -= find_life_end (loop, PATTERN (p), 
-                                               stats, p, biv);
-       }
-      while (ends_need_computing);
-    }
-
-  /* Set start_luid back to the last insn that sets the giv.  This allows
-     more combinations.  */
-  for (i = giv_count - 1; i >= 0; i--)
-    {
-      v = giv_array[stats[i].giv_number];
-      if (v->ignore)
-       continue;
-      if (INSN_UID (v->insn) < max_uid_for_loop)
-       stats[i].start_luid = INSN_LUID (v->insn);
-    }
-
-  /* Now adjust lifetime ends by taking combined givs into account.  */
-  for (i = giv_count - 1; i >= 0; i--)
-    {
-      unsigned luid;
-      int j;
-
-      v = giv_array[stats[i].giv_number];
-      if (v->ignore)
-       continue;
-      if (v->same && ! v->same->ignore)
-       {
-         j = v->same->ix;
-         luid = stats[i].start_luid;
-         /* Use unsigned arithmetic to model loop wrap-around.  */
-         if (luid - stats[j].start_luid
-             > (unsigned) stats[j].end_luid - stats[j].start_luid)
-           stats[j].end_luid = luid;
-       }
-    }
-
-  qsort (stats, giv_count, sizeof (*stats), cmp_recombine_givs_stats);
+             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;
 
-  /* Try to derive DEST_REG givs from previous DEST_REG givs with the
-     same mult_val and non-overlapping lifetime.  This reduces register
-     pressure.
-     Once we find a DEST_REG giv that is suitable to derive others from,
-     we set last_giv to this giv, and try to derive as many other DEST_REG
-     givs from it without joining overlapping lifetimes.  If we then
-     encounter a DEST_REG giv that we can't derive, we set rescan to the
-     index for this giv (unless rescan is already set).
-     When we are finished with the current LAST_GIV (i.e. the inner loop
-     terminates), we start again with rescan, which then becomes the new
-     LAST_GIV.  */
-  for (i = giv_count - 1; i >= 0; i = rescan)
-    {
-      int life_start = 0, life_end = 0;
+             g1_add_benefit += g2->benefit;
 
-      for (last_giv = 0, rescan = -1; i >= 0; i--)
-       {
-         rtx sum;
+             /* ??? 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 (! g2->replaceable && REG_USERVAR_P (g2->dest_reg))
+               g1_add_benefit -= copy_cost;
 
-         v = giv_array[stats[i].giv_number];
-         if (v->giv_type != DEST_REG || v->derived_from || v->same)
-           continue;
-         if (! last_giv)
-           {
-             /* Don't use a giv that's likely to be dead to derive
-                others - that would be likely to keep that giv alive.  */
-             if (! v->maybe_dead || v->combined_with)
+             /* To help optimize the next set of combinations, remove
+                this giv from the benefits of other potential mates.  */
+             for (l = 0; l < giv_count; ++l)
                {
-                 last_giv = v;
-                 life_start = stats[i].start_luid;
-                 life_end = stats[i].end_luid;
+                 int m = stats[l].giv_number;
+                 if (can_combine[m * giv_count + j])
+                   stats[l].total_benefit -= g2->benefit + extra_benefit;
                }
-             continue;
-           }
-         /* Use unsigned arithmetic to model loop wrap around.  */
-         if (((unsigned) stats[i].start_luid - life_start
-              >= (unsigned) life_end - life_start)
-             && ((unsigned) stats[i].end_luid - life_start
-                 > (unsigned) life_end - life_start)
-             /*  Check that the giv insn we're about to use for deriving
-                 precedes all uses of that giv.  Note that initializing the
-                 derived giv would defeat the purpose of reducing register
-                 pressure.
-                 ??? We could arrange to move the insn.  */
-             && ((unsigned) stats[i].end_luid - INSN_LUID (loop->start)
-                  > (unsigned) stats[i].start_luid - INSN_LUID (loop->start))
-             && rtx_equal_p (last_giv->mult_val, v->mult_val)
-             /* ??? Could handle libcalls, but would need more logic.  */
-             && ! find_reg_note (v->insn, REG_RETVAL, NULL_RTX)
-             /* We would really like to know if for any giv that v
-                is combined with, v->insn or any intervening biv increment
-                dominates that combined giv.  However, we
-                don't have this detailed control flow information.
-                N.B. since last_giv will be reduced, it is valid
-                anywhere in the loop, so we don't need to check the
-                validity of last_giv.
-                We rely here on the fact that v->always_executed implies that
-                there is no jump to someplace else in the loop before the
-                giv insn, and hence any insn that is executed before the
-                giv insn in the loop will have a lower luid.  */
-             && (v->always_executed || ! v->combined_with)
-             && (sum = express_from (last_giv, v))
-             /* Make sure we don't make the add more expensive.  ADD_COST
-                doesn't take different costs of registers and constants into
-                account, so compare the cost of the actual SET_SRCs.  */
-             && (rtx_cost (sum, SET)
-                 <= rtx_cost (SET_SRC (single_set (v->insn)), SET))
-             /* ??? unroll can't understand anything but reg + const_int
-                sums.  It would be cleaner to fix unroll.  */
-             && ((GET_CODE (sum) == PLUS
-                  && GET_CODE (XEXP (sum, 0)) == REG
-                  && GET_CODE (XEXP (sum, 1)) == CONST_INT)
-                 || ! unroll_p)
-             && validate_change (v->insn, &PATTERN (v->insn),
-                                 gen_rtx_SET (VOIDmode, v->dest_reg, sum), 0))
-           {
-             v->derived_from = last_giv;
-             life_end = stats[i].end_luid;
 
              if (loop_dump_stream)
-               {
-                 fprintf (loop_dump_stream,
-                          "giv at %d derived from %d as ",
-                          INSN_UID (v->insn), INSN_UID (last_giv->insn));
-                 print_rtl (loop_dump_stream, sum);
-                 putc ('\n', loop_dump_stream);
-               }
+               fprintf (loop_dump_stream,
+                        "giv at %d combined with giv at %d; new benefit %d + %d, lifetime %d\n",
+                        INSN_UID (g2->insn), INSN_UID (g1->insn),
+                        g1->benefit, g1_add_benefit, g1->lifetime);
+           }
+       }
+
+      /* To help optimize the next set of combinations, remove
+        this giv from the benefits of other potential mates.  */
+      if (g1->combined_with)
+       {
+         for (j = 0; j < giv_count; ++j)
+           {
+             int m = stats[j].giv_number;
+             if (can_combine[m * giv_count + i])
+               stats[j].total_benefit -= g1->benefit + extra_benefit;
            }
-         else if (rescan < 0)
-           rescan = i;
+
+         g1->benefit += g1_add_benefit;
+
+         /* We've finished with this giv, and everything it touched.
+            Restart the combination so that proper weights for the
+            rest of the givs are properly taken into account.  */
+         /* ??? Ideally we would compact the arrays at this point, so
+            as to not cover old ground.  But sanely compacting
+            can_combine is tricky.  */
+         goto restart;
        }
     }
 
   /* Clean up.  */
-  free (giv_array);
   free (stats);
+  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 ();
-  result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 0);
+  /* 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.  */
+
+static void
+loop_regs_update (loop, seq)
+     const struct loop *loop ATTRIBUTE_UNUSED;
+     rtx seq;
+{
+  rtx insn;
+
+  /* Update register info for alias analysis.  */
 
-  /* It is entirely possible that the expansion created lots of new
-     registers.  Iterate over the sequence we just created and
-     record them all.  */
+  if (seq == NULL_RTX)
+    return;
 
-  if (GET_CODE (seq) == SEQUENCE)
+  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
@@ -7859,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 */
@@ -7872,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 ();
@@ -7888,18 +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;
-  struct obstack *old_rtl_obstack = rtl_obstack;
-  char *storage = (char *) obstack_alloc (&temp_obstack, 0);
-  int win = 1;
+  int win, n_insns;
 
   /* If only one is constant, make it B.  */
   if (GET_CODE (a) == CONST_INT)
@@ -7917,34 +8043,33 @@ product_cheap_p (a, b)
      code for the multiply and see if a call or multiply, or long sequence
      of insns is generated.  */
 
-  rtl_obstack = &temp_obstack;
   start_sequence ();
-  expand_mult (GET_MODE (a), a, b, NULL_RTX, 0);
-  tmp = gen_sequence ();
+  expand_mult (GET_MODE (a), a, b, NULL_RTX, 1);
+  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)
@@ -7954,11 +8079,6 @@ product_cheap_p (a, b)
           && GET_CODE (SET_SRC (XVECEXP (tmp, 0, 0))) == MULT)
     win = 0;
 
-  /* Free any storage we obtained in generating this multiply and restore rtl
-     allocation to its normal obstack.  */
-  obstack_free (&temp_obstack, storage);
-  rtl_obstack = old_rtl_obstack;
-
   return win;
 }
 \f
@@ -8031,7 +8151,7 @@ check_dbra_loop (loop, insn_count)
     rtx jump1;
     if ((jump1 = prev_nonnote_insn (first_compare)) != loop->cont)
       if (GET_CODE (jump1) == JUMP_INSN)
-        return 0;
+       return 0;
   }
 
   /* Check all of the bivs to see if the compare uses one of them.
@@ -8039,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
@@ -8131,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
@@ -8148,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
@@ -8164,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)
@@ -8191,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
@@ -8206,7 +8340,7 @@ check_dbra_loop (loop, insn_count)
                  if (v->giv_type == DEST_REG
                      && reg_mentioned_p (v->dest_reg,
                                          PATTERN (loop_info->first_loop_store_insn))
-                     && loop_insn_first_p (loop_info->first_loop_store_insn, 
+                     && loop_insn_first_p (loop_info->first_loop_store_insn,
                                            v->insn))
                    reversible_mem_store = 0;
                }
@@ -8224,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
-             + the_movables.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;
 
@@ -8376,10 +8511,8 @@ 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);
-             new_add_val = GEN_INT (- INTVAL (bl->biv->add_val));
+             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
                 to generate a SUB.
@@ -8390,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));
@@ -8418,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
@@ -8441,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.  */
@@ -8463,27 +8584,26 @@ check_dbra_loop (loop, insn_count)
 
              /* Inc LABEL_NUSES so that delete_insn will
                 not delete the label.  */
-             LABEL_NUSES (XEXP (jump_label, 0)) ++;
+             LABEL_NUSES (XEXP (jump_label, 0))++;
 
              /* Emit an insn after the end of the loop to set the biv's
                 proper exit value if it is used anywhere outside the loop.  */
              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);
 
@@ -8528,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;)
@@ -8568,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
@@ -8583,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)
            {
@@ -8609,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,
@@ -8627,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",
@@ -8641,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)
@@ -8654,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
@@ -8674,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
@@ -8693,22 +8821,6 @@ biv_elimination_giv_has_0_offset (biv, giv, insn)
              && loop_insn_first_p (insn, giv->insn))))
     return 0;
 
-  /* If the giv V was derived from another giv, and INSN does
-     not occur between the giv insn and the biv insn, then we'd
-     have to adjust the value used here.  This is rare, so we don't
-     bother to make this possible.  */
-  if (giv->derived_from
-      && ! (giv->always_executed
-           && loop_insn_first_p (giv->insn, insn)
-           && loop_insn_first_p (insn, biv->insn)))
-    return 0;
-  if (giv->same
-      && giv->same->derived_from
-      && ! (giv->same->always_executed
-           && loop_insn_first_p (giv->same->insn, insn)
-           && loop_insn_first_p (insn, biv->insn)))
-    return 0;
-
   return 1;
 }
 
@@ -8717,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;
@@ -8812,7 +8926,7 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                    || GET_CODE (v->add_val) == LABEL_REF
                    || GET_CODE (v->add_val) == CONST
                    || (GET_CODE (v->add_val) == REG
-                       && REGNO_POINTER_FLAG (REGNO (v->add_val)))))
+                       && REG_POINTER (v->add_val))))
              {
                if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
                  continue;
@@ -8838,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.  */
@@ -8876,13 +8991,29 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                    || GET_CODE (v->add_val) == LABEL_REF
                    || GET_CODE (v->add_val) == CONST
                    || (GET_CODE (v->add_val) == REG
-                       && REGNO_POINTER_FLAG (REGNO (v->add_val))))
+                       && REG_POINTER (v->add_val)))
                && ! v->ignore && ! v->maybe_dead && v->always_computable
                && v->mode == mode)
              {
                if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
                  continue;
 
+               /* Don't eliminate if the linear combination that makes up
+                  the giv overflows when it is applied to ARG.  */
+               if (GET_CODE (arg) == CONST_INT)
+                 {
+                   rtx add_val;
+
+                   if (GET_CODE (v->add_val) == CONST_INT)
+                     add_val = v->add_val;
+                   else
+                     add_val = const0_rtx;
+
+                   if (const_mult_add_overflow_p (arg, v->mult_val,
+                                                  add_val, mode, 1))
+                     continue;
+                 }
+
                if (! eliminate_p)
                  return 1;
 
@@ -8893,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;
              }
@@ -8938,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 ())
@@ -8974,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;
@@ -9009,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)
@@ -9055,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;
        }
@@ -9103,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)
@@ -9120,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)
@@ -9130,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
-      && uid_luid[REGNO_LAST_UID (REGNO (x))] < uid_luid[INSN_UID (insn)])
-    REGNO_LAST_UID (REGNO (x)) = INSN_UID (insn);
+      && REGNO_LAST_LUID (REGNO (x)) < INSN_LUID (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')
@@ -9162,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.  */
 
@@ -9187,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);
@@ -9196,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;
@@ -9210,10 +9348,10 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
      in cse.c  */
 
   while (GET_RTX_CLASS (code) == '<'
-         && op1 == CONST0_RTX (GET_MODE (op0))
+        && 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
@@ -9250,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
@@ -9286,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))) == '<'))
@@ -9306,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))) == '<'
@@ -9316,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);
            }
@@ -9337,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;
            }
 
@@ -9376,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
@@ -9385,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:
@@ -9403,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);
 }
@@ -9426,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.  */
@@ -9465,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))
@@ -9553,7 +9684,7 @@ insert_loop_mem (mem, data)
       else
        loop_info->mems_allocated = 32;
 
-      loop_info->mems = (loop_mem_info*)
+      loop_info->mems = (loop_mem_info *)
        xrealloc (loop_info->mems,
                  loop_info->mems_allocated * sizeof (loop_mem_info));
     }
@@ -9571,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;
 
-  load_mems (loop);
+  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));
 
-  /* Recalculate regs->set_in_loop and friends since load_mems may have
-     created new registers.  */
-  if (max_reg_num () > nregs)
+      /* 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++)
     {
-      int i;
-      int old_nregs;
+      regs->array[i].set_in_loop = 0;
+      regs->array[i].may_not_optimize = 0;
+      regs->array[i].single_usage = NULL_RTX;
+    }
 
-      old_nregs = nregs;
-      nregs = max_reg_num ();
+  last_set = (rtx *) xcalloc (regs->num, sizeof (rtx));
 
-      if ((unsigned) nregs > regs->set_in_loop->num_elements)
+  /* 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))
        {
-         /* 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);
+         /* Record registers that have exactly one use.  */
+         find_single_use_in_loop (regs, insn, PATTERN (insn));
+
+         /* Include uses in REG_EQUAL notes.  */
+         if (REG_NOTES (insn))
+           find_single_use_in_loop (regs, insn, REG_NOTES (insn));
+
+         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);
+           }
        }
-      /* Clear the arrays */
-      bzero ((char *) &regs->set_in_loop->data, nregs * sizeof (int));
-      bzero ((char *) &regs->may_not_optimize->data, nregs * sizeof (char));
-      bzero ((char *) &regs->single_usage->data, nregs * sizeof (rtx));
 
-      count_loop_regs_set (loop, regs->may_not_optimize, regs->single_usage,
-                          insn_count, nregs);
+      if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
+       memset (last_set, 0, regs->num * sizeof (rtx));
+
+      /* 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)
+       {
+         rtx link;
+         for (link = CALL_INSN_FUNCTION_USAGE (insn); 
+              link; 
+              link = XEXP (link, 1))
+           {
+             rtx op, reg;
+
+             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.  */
@@ -9642,33 +9860,26 @@ 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 = 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;
 
-  /* Find start of the extended basic block that enters the loop.  */
-  for (p = loop->start;
-       PREV_INSN (p) && GET_CODE (p) != CODE_LABEL;
-       p = PREV_INSN (p))
-    ;
-
-  cselib_init ();
-
-  /* Build table of mems that get set to constant values before the
-     loop.  */
-  for (; p != loop->start; p = NEXT_INSN (p))
-    cselib_process_insn (p);
-
-  /* Check to see if it's possible that some instructions in the
-     loop are never executed.  */
+  /* We cannot use next_label here because it skips over normal insns.  */
+  end_label = next_nonnote_insn (loop->end);
+  if (end_label && GET_CODE (end_label) != CODE_LABEL)
+    end_label = NULL_RTX;
+
+  /* Check to see if it's possible that some instructions in the loop are
+     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)
@@ -9685,6 +9896,18 @@ load_mems (loop)
                     && NEXT_INSN (NEXT_INSN (p)) == loop->end
                     && any_uncondjump_p (p)))
        {
+         /* 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 (/* 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))
            /* Something complicated.  */
            maybe_never = 1;
@@ -9697,6 +9920,20 @@ load_mems (loop)
        maybe_never = 1;
     }
 
+  /* Find start of the extended basic block that enters the loop.  */
+  for (p = loop->start;
+       PREV_INSN (p) && GET_CODE (p) != CODE_LABEL;
+       p = PREV_INSN (p))
+    ;
+  prev_ebb_head = p;
+
+  cselib_init ();
+
+  /* Build table of mems that get set to constant values before the
+     loop.  */
+  for (; p != loop->start; p = NEXT_INSN (p))
+    cselib_process_insn (p);
+
   /* Actually move the MEMs.  */
   for (i = 0; i < loop_info->mems_idx; ++i)
     {
@@ -9779,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;
@@ -9800,28 +10037,38 @@ 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)));
 
-             /* See if this copies the mem from a register that isn't
+             /* See if this copies the mem from a register that isn't
                 modified afterwards.  We'll try to remove the
                 redundant copy later on by doing a little register
                 renaming and copy propagation.   This will help
                 to untangle things for the BIV detection code.  */
-             if (set
-                 && ! maybe_never
-                 && 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
-                 && 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 (set
+                 && ! maybe_never
+                 && GET_CODE (SET_SRC (set)) == REG
+                 && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER
+                 && REGNO (SET_SRC (set)) < last_max_reg
+                 && 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)));
+
+             /* 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
@@ -9829,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
@@ -9851,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
@@ -9877,21 +10126,26 @@ 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)
            {
              if (label == NULL_RTX)
                {
-                 /* We must compute the former
-                    right-after-the-end label before we insert
-                    the new one.  */
-                 end_label = next_label (loop->end);
                  label = gen_label_rtx ();
                  emit_label_after (label, loop->end);
                }
@@ -9899,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)
@@ -9929,26 +10183,18 @@ load_mems (loop)
        }
     }
 
-  if (label != NULL_RTX)
+  if (label != NULL_RTX && end_label != NULL_RTX)
     {
       /* 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;
        }
     }
 
@@ -10035,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)
@@ -10046,17 +10301,50 @@ 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
@@ -10070,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);
@@ -10080,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
@@ -10093,14 +10381,14 @@ try_swap_copy_prop (loop, replacement, regno)
     {
       rtx prev_insn;
       rtx prev_set;
-      
+
       /* Some DEF-USE info would come in handy here to make this
         function more general.  For now, just check the previous insn
         which is the most likely candidate for setting 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)
@@ -10108,7 +10396,7 @@ try_swap_copy_prop (loop, replacement, regno)
          /* We have:
             (set (reg regno) (expr))
             (set (reg new_regno) (reg regno))
-            
+
             so try converting this to:
             (set (reg new_regno) (expr))
             (set (reg regno) (reg new_regno))
@@ -10128,9 +10416,9 @@ try_swap_copy_prop (loop, replacement, regno)
          if (apply_change_group ())
            {
              if (loop_dump_stream)
-               fprintf (loop_dump_stream, 
-                        "  Swapped set of reg %d at %d with reg %d at %d.\n", 
-                        regno, INSN_UID (insn), 
+               fprintf (loop_dump_stream,
+                        "  Swapped set of reg %d at %d with reg %d at %d.\n",
+                        regno, INSN_UID (insn),
                         new_regno, INSN_UID (prev_insn));
 
              /* Update first use of REGNO.  */
@@ -10145,7 +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
@@ -10156,7 +10470,7 @@ replace_loop_mem (mem, data)
      rtx *mem;
      void *data;
 {
-  loop_replace_args *args = (loop_replace_args *)data;
+  loop_replace_args *args = (loop_replace_args *) data;
   rtx m = *mem;
 
   if (m == NULL_RTX)
@@ -10187,13 +10501,13 @@ replace_loop_mem (mem, data)
   return 0;
 }
 
-
 static void
-replace_loop_mems (insn, mem, reg)
-      rtx insn;
-      rtx mem;
-      rtx reg;
-{          
+replace_loop_mems (insn, mem, reg, written)
+     rtx insn;
+     rtx mem;
+     rtx reg;
+     int written;
+{
   loop_replace_args args;
 
   args.insn = insn;
@@ -10201,11 +10515,30 @@ 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
-   to the rtx being scanned.  DATA is actually a pointer to 
+   to the rtx being scanned.  DATA is actually a pointer to
    a structure of arguments.  */
 
 static int
@@ -10214,7 +10547,7 @@ replace_loop_reg (px, data)
      void *data;
 {
   rtx x = *px;
-  loop_replace_args *args = (loop_replace_args *)data;
+  loop_replace_args *args = (loop_replace_args *) data;
 
   if (x == NULL_RTX)
     return 0;
@@ -10225,7 +10558,6 @@ replace_loop_reg (px, data)
   return 0;
 }
 
-
 static void
 replace_loop_regs (insn, reg, replacement)
      rtx insn;
@@ -10240,37 +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).  */
+
+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);
+}
 
 
-/* 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.  */
+/* 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.  */
 
-static int
-replace_label (x, data)
-     rtx *x;
-     void *data;
+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)
 
@@ -10283,10 +10906,11 @@ replace_label (x, data)
 
 #define LOOP_INSN_UID(INSN) ((INSN) ? INSN_UID (INSN) : -1)
 
-static void loop_dump_aux (loop, file, verbose)
+static void
+loop_dump_aux (loop, file, verbose)
      const struct loop *loop;
      FILE *file;
-     int verbose;
+     int verbose ATTRIBUTE_UNUSED;
 {
   rtx label;
 
@@ -10299,7 +10923,7 @@ static void loop_dump_aux (loop, file, verbose)
       || GET_CODE (PREV_INSN (loop->first->head)) != NOTE
       || NOTE_LINE_NUMBER (PREV_INSN (loop->first->head))
       != NOTE_INSN_LOOP_BEG)
-    fprintf (file, ";;  No NOTE_INSN_LOOP_BEG at %d\n", 
+    fprintf (file, ";;  No NOTE_INSN_LOOP_BEG at %d\n",
             INSN_UID (PREV_INSN (loop->first->head)));
   if (! NEXT_INSN (loop->last->end)
       || GET_CODE (NEXT_INSN (loop->last->end)) != NOTE
@@ -10324,7 +10948,7 @@ static void loop_dump_aux (loop, file, verbose)
               LOOP_INSN_UID (loop->end));
       fprintf (file, ";;  top %d (%d), scan start %d (%d)\n",
               LOOP_BLOCK_NUM (loop->top),
-              LOOP_INSN_UID (loop->top) ,
+              LOOP_INSN_UID (loop->top),
               LOOP_BLOCK_NUM (loop->scan_start),
               LOOP_INSN_UID (loop->scan_start));
       fprintf (file, ";;  exit_count %d", loop->exit_count);
@@ -10338,7 +10962,7 @@ static void loop_dump_aux (loop, file, verbose)
            }
        }
       fputs ("\n", file);
-      
+
       /* This can happen when a marked loop appears as two nested loops,
         say from while (a || b) {}.  The inner loop won't match
         the loop markers but the outer one will.  */
@@ -10346,7 +10970,6 @@ static void loop_dump_aux (loop, file, verbose)
        fprintf (file, ";;  NOTE_INSN_LOOP_CONT not in loop latch\n");
     }
 }
-  
 
 /* Call this function from the debugger to dump LOOP.  */
 
@@ -10356,3 +10979,12 @@ debug_loop (loop)
 {
   flow_loop_dump (loop, stderr, loop_dump_aux, 1);
 }
+
+/* Call this function from the debugger to dump LOOPS.  */
+
+void
+debug_loops (loops)
+     const struct loops *loops;
+{
+  flow_loops_dump (loops, stderr, loop_dump_aux, 1);
+}