OSDN Git Service

Fix date on last entry.
[pf3gnuchains/gcc-fork.git] / gcc / loop.c
index cc278dc..cbb1731 100644 (file)
@@ -1,5 +1,6 @@
 /* Perform various loop optimizations, including strength reduction.
-   Copyright (C) 1987, 88, 89, 91-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+   1998, 1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -37,9 +38,11 @@ Boston, MA 02111-1307, USA.  */
 #include "config.h"
 #include "system.h"
 #include "rtl.h"
+#include "tm_p.h"
 #include "obstack.h"
 #include "function.h"
 #include "expr.h"
+#include "basic-block.h"
 #include "insn-config.h"
 #include "insn-flags.h"
 #include "regs.h"
@@ -48,14 +51,10 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "real.h"
 #include "loop.h"
+#include "cselib.h"
 #include "except.h"
 #include "toplev.h"
 
-/* Information about the loop being processed used to compute
-   the number of loop iterations for loop unrolling and doloop
-   optimization.  */
-static struct loop_info this_loop_info;
-
 /* Vector mapping INSN_UIDs to luids.
    The luids are like uids but increase monotonically always.
    We use them to see whether a jump comes from outside a given loop.  */
@@ -65,7 +64,7 @@ int *uid_luid;
 /* Indexed by INSN_UID, contains the ordinal giving the (innermost) loop
    number the insn is contained in.  */
 
-int *uid_loop_num;
+struct loop **uid_loop;
 
 /* 1 + largest uid of any insn.  */
 
@@ -80,52 +79,6 @@ static int max_luid;
 
 static int max_loop_num;
 
-/* Indexed by loop number, contains the first and last insn of each loop.  */
-
-static rtx *loop_number_loop_starts, *loop_number_loop_ends;
-
-/* Likewise for the continue insn */
-static rtx *loop_number_loop_cont;
-
-/* The first code_label that is reached in every loop iteration.
-   0 when not computed yet, initially const0_rtx if a jump couldn't be
-   followed.
-   Also set to 0 when there is no such label before the NOTE_INSN_LOOP_CONT
-   of this loop, or in verify_dominator, if a jump couldn't be followed.  */
-static rtx *loop_number_cont_dominator;
-
-/* For each loop, gives the containing loop number, -1 if none.  */
-
-int *loop_outer_loop;
-
-#ifdef HAVE_decrement_and_branch_on_count
-/* Records whether resource in use by inner loop.  */
-
-int *loop_used_count_register;
-#endif  /* HAVE_decrement_and_branch_on_count */
-
-/* Indexed by loop number, contains a nonzero value if the "loop" isn't
-   really a loop (an insn outside the loop branches into it).  */
-
-static char *loop_invalid;
-
-/* Indexed by loop number, links together all LABEL_REFs which refer to
-   code labels outside the loop.  Used by routines that need to know all
-   loop exits, such as final_biv_value and final_giv_value.
-
-   This does not include loop exits due to return instructions.  This is
-   because all bivs and givs are pseudos, and hence must be dead after a
-   return, so the presense of a return does not affect any of the
-   optimizations that use this info.  It is simpler to just not include return
-   instructions on this list.  */
-
-rtx *loop_number_exit_labels;
-
-/* Indexed by loop number, counts the number of LABEL_REFs on
-   loop_number_exit_labels for this loop and all loops nested inside it.  */
-
-int *loop_number_exit_count;
-
 /* Indexed by register number, contains the number of times the reg
    is set during the loop being scanned.
    During code motion, a negative value indicates a reg that has been
@@ -196,6 +149,11 @@ static int loop_mems_allocated;
 
 static int unknown_address_altered;
 
+/* The above doesn't count any readonly memory locations that are stored.
+   This does.  */
+
+static int unknown_constant_address_altered;
+
 /* Count of movable (i.e. invariant) instructions discovered in the loop.  */
 static int num_movables;
 
@@ -204,7 +162,10 @@ static int num_mem_sets;
 
 /* Bound on pseudo register number before loop optimization.
    A pseudo has valid regscan info if its number is < max_reg_before_loop.  */
-int 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.
@@ -233,7 +194,7 @@ struct movable
                                   of any registers used within the LIBCALL.  */
   int consec;                  /* Number of consecutive following insns 
                                   that must be moved with this one.  */
-  int regno;                   /* The register it sets */
+  unsigned int regno;          /* The register it sets */
   short lifetime;              /* lifetime of that register;
                                   may be adjusted when matching movables
                                   that load the same value are found.  */
@@ -270,67 +231,83 @@ FILE *loop_dump_stream;
 
 /* Forward declarations.  */
 
-static void verify_dominator PROTO((int));
-static void find_and_verify_loops PROTO((rtx));
-static void mark_loop_jump PROTO((rtx, int));
-static void prescan_loop PROTO((rtx, rtx, struct loop_info *));
-static int reg_in_basic_block_p PROTO((rtx, rtx));
-static int consec_sets_invariant_p PROTO((rtx, int, rtx));
-static int labels_in_range_p PROTO((rtx, int));
-static void count_one_set PROTO((rtx, rtx, varray_type, rtx *));
-
-static void count_loop_regs_set PROTO((rtx, rtx, varray_type, varray_type,
-                                      int *, int)); 
-static void note_addr_stored PROTO((rtx, rtx));
-static int loop_reg_used_before_p PROTO((rtx, rtx, rtx, rtx, rtx));
-static void scan_loop PROTO((rtx, rtx, rtx, int, int));
+static void verify_dominator PARAMS ((struct loop *));
+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 *));
+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 ((rtx, rtx, varray_type, rtx *));
+
+static void count_loop_regs_set PARAMS ((rtx, rtx, varray_type, varray_type,
+                                        int *, int)); 
+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));
+static void scan_loop PARAMS ((struct loop*, int, int));
 #if 0
-static void replace_call_address PROTO((rtx, rtx, rtx));
+static void replace_call_address PARAMS ((rtx, rtx, rtx));
 #endif
-static rtx skip_consec_insns PROTO((rtx, int));
-static int libcall_benefit PROTO((rtx));
-static void ignore_some_movables PROTO((struct movable *));
-static void force_movables PROTO((struct movable *));
-static void combine_movables PROTO((struct movable *, int));
-static int regs_match_p PROTO((rtx, rtx, struct movable *));
-static int rtx_equal_for_loop_p PROTO((rtx, rtx, struct movable *));
-static void add_label_notes PROTO((rtx, rtx));
-static void move_movables PROTO((struct movable *, int, int, rtx, rtx, int));
-static int count_nonfixed_reads PROTO((rtx));
-static void strength_reduce PROTO((rtx, rtx, rtx, int, rtx, rtx, 
-                                  struct loop_info *, rtx, int, int));
-static void find_single_use_in_loop PROTO((rtx, rtx, varray_type));
-static int valid_initial_value_p PROTO((rtx, rtx, int, rtx));
-static void find_mem_givs PROTO((rtx, rtx, int, int, rtx, rtx));
-static void record_biv PROTO((struct induction *, rtx, rtx, rtx, rtx, rtx *, int, int));
-static void check_final_value PROTO((struct induction *, rtx, rtx, 
-                                    unsigned HOST_WIDE_INT));
-static void record_giv PROTO((struct induction *, rtx, rtx, rtx, rtx, rtx, int, enum g_types, int, int, rtx *, rtx, rtx));
-static void update_giv_derive PROTO((rtx));
-static int basic_induction_var PROTO((rtx, enum machine_mode, rtx, rtx, rtx *, rtx *, rtx **));
-static rtx simplify_giv_expr PROTO((rtx, int *));
-static int general_induction_var PROTO((rtx, rtx *, rtx *, rtx *, int, int *));
-static int consec_sets_giv PROTO((int, rtx, rtx, rtx, rtx *, rtx *, rtx *));
-static int check_dbra_loop PROTO((rtx, int, rtx, struct loop_info *));
-static rtx express_from_1 PROTO((rtx, rtx, rtx));
-static rtx combine_givs_p PROTO((struct induction *, struct induction *));
-static void combine_givs PROTO((struct iv_class *));
+static rtx skip_consec_insns PARAMS ((rtx, int));
+static int libcall_benefit PARAMS ((rtx));
+static void ignore_some_movables PARAMS ((struct movable *));
+static void force_movables PARAMS ((struct movable *));
+static void combine_movables PARAMS ((struct movable *, int));
+static int regs_match_p PARAMS ((rtx, rtx, struct movable *));
+static int rtx_equal_for_loop_p PARAMS ((rtx, rtx, struct movable *));
+static void add_label_notes PARAMS ((rtx, rtx));
+static void move_movables PARAMS ((struct loop *loop, struct movable *, 
+                                  int, int, int));
+static int count_nonfixed_reads PARAMS ((const struct loop *, rtx));
+static void strength_reduce PARAMS ((struct loop *, int, int, int));
+static void find_single_use_in_loop PARAMS ((rtx, rtx, varray_type));
+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 induction *, rtx, rtx, rtx, rtx, rtx *, 
+                               int, int, int));
+static void check_final_value PARAMS ((const struct loop *,
+                                      struct induction *));
+static void record_giv PARAMS ((const struct loop *, struct induction *, 
+                               rtx, rtx, rtx, rtx, rtx, int, enum g_types, 
+                               int, int, rtx *));
+static void update_giv_derive PARAMS ((const struct loop *, rtx));
+static int basic_induction_var PARAMS ((const struct loop *, rtx, 
+                                       enum machine_mode, rtx, rtx,
+                                       rtx *, rtx *, rtx **, int *));
+static rtx simplify_giv_expr PARAMS ((const struct loop *, rtx, int *));
+static int general_induction_var PARAMS ((const struct loop *loop, rtx, rtx *,
+                                         rtx *, rtx *, int, int *));
+static int consec_sets_giv PARAMS ((const struct loop *, int, rtx,
+                                   rtx, rtx, rtx *, rtx *, 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 void combine_givs PARAMS ((struct iv_class *));
 struct recombine_givs_stats;
-static int find_life_end PROTO((rtx, struct recombine_givs_stats *, rtx, rtx));
-static void recombine_givs PROTO((struct iv_class *, rtx, rtx, int));
-static int product_cheap_p PROTO((rtx, rtx));
-static int maybe_eliminate_biv PROTO((struct iv_class *, rtx, rtx, int, int, int));
-static int maybe_eliminate_biv_1 PROTO((rtx, rtx, struct iv_class *, int, rtx));
-static int last_use_this_basic_block PROTO((rtx, rtx));
-static void record_initial PROTO((rtx, rtx));
-static void update_reg_last_use PROTO((rtx, rtx));
-static rtx next_insn_in_loop PROTO((rtx, rtx, rtx, rtx));
-static void load_mems_and_recount_loop_regs_set PROTO((rtx, rtx, rtx,
-                                                      rtx, int *));
-static void load_mems PROTO((rtx, rtx, rtx, rtx));
-static int insert_loop_mem PROTO((rtx *, void *));
-static int replace_loop_mem PROTO((rtx *, void *));
-static int replace_label PROTO((rtx *, void *));
+static int find_life_end PARAMS ((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));
+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 load_mems PARAMS ((const struct loop *));
+static int insert_loop_mem PARAMS ((rtx *, void *));
+static int replace_loop_mem PARAMS ((rtx *, void *));
+static int replace_loop_reg PARAMS ((rtx *, void *));
+static void note_reg_stored PARAMS ((rtx, rtx, void *));
+static void try_copy_prop PARAMS ((const struct loop *, rtx, unsigned int));
+static int replace_label PARAMS ((rtx *, void *));
 
 typedef struct rtx_and_int {
   rtx r;
@@ -350,19 +327,19 @@ typedef struct rtx_pair {
 
 #ifdef HAVE_decrement_and_branch_on_count
 /* Test whether BCT applicable and safe.  */
-static void insert_bct PROTO((rtx, rtx, struct loop_info *));
+static void insert_bct PARAMS ((struct loop *));
 
 /* Auxiliary function that inserts the BCT pattern into the loop.  */
-static void instrument_loop_bct PROTO((rtx, rtx, rtx));
+static void instrument_loop_bct PARAMS ((rtx, rtx, rtx));
 #endif /* HAVE_decrement_and_branch_on_count */
 
 /* Indirect_jump_in_function is computed once per function.  */
 int indirect_jump_in_function = 0;
-static int indirect_jump_in_function_p PROTO((rtx));
+static int indirect_jump_in_function_p PARAMS ((rtx));
 
-static int compute_luids PROTO((rtx, rtx, int));
+static int compute_luids PARAMS ((rtx, rtx, int));
 
-static int biv_elimination_giv_has_0_offset PROTO((struct induction *,
+static int biv_elimination_giv_has_0_offset PARAMS ((struct induction *,
                                                   struct induction *, rtx));
 \f
 /* Relative gain of eliminating various kinds of operations.  */
@@ -450,15 +427,16 @@ loop_optimize (f, dumpfile, unroll_p, bct_p)
 {
   register rtx insn;
   register int i;
+  struct loops loops_data;
+  struct loops *loops = &loops_data;
+  struct loop_info *loops_info;
 
   loop_dump_stream = dumpfile;
 
   init_recog_no_volatile ();
 
   max_reg_before_loop = max_reg_num ();
-
-  moved_once = (char *) alloca (max_reg_before_loop);
-  bzero (moved_once, max_reg_before_loop);
+  loop_max_reg = max_reg_before_loop;
 
   regs_may_share = 0;
 
@@ -476,41 +454,35 @@ loop_optimize (f, dumpfile, unroll_p, bct_p)
   if (max_loop_num == 0)
     return;
 
+  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;
 
-  uid_luid = (int *) alloca (max_uid_for_loop * sizeof (int));
-  uid_loop_num = (int *) alloca (max_uid_for_loop * sizeof (int));
-
-  bzero ((char *) uid_luid, max_uid_for_loop * sizeof (int));
-  bzero ((char *) uid_loop_num, max_uid_for_loop * sizeof (int));
+  uid_luid = (int *) xcalloc (max_uid_for_loop, sizeof (int));
+  uid_loop = (struct loop **) xcalloc (max_uid_for_loop, 
+                                      sizeof (struct loop *));
 
-  /* Allocate tables for recording each loop.  We set each entry, so they need
-     not be zeroed.  */
-  loop_number_loop_starts = (rtx *) alloca (max_loop_num * sizeof (rtx));
-  loop_number_loop_ends = (rtx *) alloca (max_loop_num * sizeof (rtx));
-  loop_number_loop_cont = (rtx *) alloca (max_loop_num * sizeof (rtx));
-  loop_number_cont_dominator = (rtx *) alloca (max_loop_num * sizeof (rtx));
-  loop_outer_loop = (int *) alloca (max_loop_num * sizeof (int));
-  loop_invalid = (char *) alloca (max_loop_num * sizeof (char));
-  loop_number_exit_labels = (rtx *) alloca (max_loop_num * sizeof (rtx));
-  loop_number_exit_count = (int *) alloca (max_loop_num * sizeof (int));
-
-#ifdef HAVE_decrement_and_branch_on_count
-  /* Allocate for BCT optimization */
-  loop_used_count_register = (int *) alloca (max_loop_num * sizeof (int));
-  bzero ((char *) loop_used_count_register, max_loop_num * sizeof (int));
-#endif  /* HAVE_decrement_and_branch_on_count */
+  /* Allocate storage for array of loops.  */
+  loops->array = (struct loop *)
+    xcalloc (loops->num, sizeof (struct loop));
 
   /* Find and process each loop.
      First, find them, and record them in order of their beginnings.  */
-  find_and_verify_loops (f);
+  find_and_verify_loops (f, loops);
+
+  /* Allocate and initialize auxiliary loop information.  */
+  loops_info = xcalloc (loops->num, sizeof (struct loop_info));
+  for (i = 0; i < loops->num; i++)
+    loops->array[i].aux = loops_info + i;
 
   /* Now find all register lifetimes.  This must be done after
      find_and_verify_loops, because it might reorder the insns in the
      function.  */
-  reg_scan (f, max_reg_num (), 1);
+  reg_scan (f, max_reg_before_loop, 1);
 
   /* This must occur after reg_scan so that registers created by gcse
      will have entries in the register tables.
@@ -526,8 +498,9 @@ loop_optimize (f, dumpfile, unroll_p, bct_p)
   /* Now reset it to the actual size we need.  See above.  */
   max_uid_for_loop = get_max_uid ();
 
-  /* find_and_verify_loops has already called compute_luids, but it might
-     have rearranged code afterwards, so we need to recompute the luids now.  */
+  /* 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);
 
   /* Don't leave gaps in uid_luid for insns that have been
@@ -545,66 +518,68 @@ loop_optimize (f, dumpfile, unroll_p, bct_p)
     if (uid_luid[i] == 0)
       uid_luid[i] = uid_luid[i - 1];
 
-  /* Create a mapping from loops to BLOCK tree nodes.  */
-  if (unroll_p && write_symbols != NO_DEBUG)
-    find_loop_tree_blocks ();
-
   /* Determine if the function has indirect jump.  On some systems
      this prevents low overhead loop instructions from being used.  */
   indirect_jump_in_function = indirect_jump_in_function_p (f);
 
   /* Now scan the loops, last ones first, since this means inner ones are done
      before outer ones.  */
-  for (i = max_loop_num-1; i >= 0; i--)
-    if (! loop_invalid[i] && loop_number_loop_ends[i])
-      scan_loop (loop_number_loop_starts[i], loop_number_loop_ends[i],
-                loop_number_loop_cont[i], unroll_p, bct_p);
+  for (i = max_loop_num - 1; i >= 0; i--)
+    {
+      struct loop *loop = &loops->array[i];
+
+      if (! loop->invalid && loop->end)
+       scan_loop (loop, unroll_p, bct_p);
+    }
 
-  /* If debugging and unrolling loops, we must replicate the tree nodes
-     corresponding to the blocks inside the loop, so that the original one
-     to one mapping will remain.  */
-  if (unroll_p && write_symbols != NO_DEBUG)
-    unroll_block_trees ();
+  /* 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);
+  free (loops->array);
 }
 \f
 /* Returns the next insn, in execution order, after INSN.  START and
    END are the NOTE_INSN_LOOP_BEG and NOTE_INSN_LOOP_END for the loop,
-   respectively.  LOOP_TOP, if non-NULL, is the top of the loop in the
+   respectively.  LOOP->TOP, if non-NULL, is the top of the loop in the
    insn-stream; it is used with loops that are entered near the
    bottom.  */
 
 static rtx
-next_insn_in_loop (insn, start, end, loop_top)
+next_insn_in_loop (loop, insn)
+     const struct loop *loop;
      rtx insn;
-     rtx start;
-     rtx end;
-     rtx loop_top;
 {
   insn = NEXT_INSN (insn);
 
-  if (insn == end)
+  if (insn == loop->end)
     {
-      if (loop_top)
+      if (loop->top)
        /* Go to the top of the loop, and continue there.  */
-       insn = loop_top;
+       insn = loop->top;
       else
        /* We're done.  */
        insn = NULL_RTX;
     }
 
-  if (insn == start)
+  if (insn == loop->scan_start)
     /* We're done.  */
     insn = NULL_RTX;
 
   return insn;
 }
 
-/* Optimize one loop whose start is LOOP_START and end is END.
-   LOOP_START is the NOTE_INSN_LOOP_BEG and END is the matching
-   NOTE_INSN_LOOP_END.
-   LOOP_CONT is the NOTE_INSN_LOOP_CONT.  */
+/* Optimize one loop described by LOOP.  */
 
 /* ??? Could also move memory writes out of loops if the destination address
    is invariant, the source is invariant, the memory write is not volatile,
@@ -613,29 +588,30 @@ next_insn_in_loop (insn, start, end, loop_top)
    write, then we can also mark the memory read as invariant.  */
 
 static void
-scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
-     rtx loop_start, end, loop_cont;
+scan_loop (loop, unroll_p, bct_p)
+     struct loop *loop;
      int unroll_p, bct_p;
 {
   register int i;
+  rtx loop_start = loop->start;
+  rtx loop_end = loop->end;
+  /* Additional information about the current loop being processed
+     that is used to compute the number of loop iterations for loop
+     unrolling and doloop optimization.  */
+  struct loop_info *loop_info = LOOP_INFO (loop);
   rtx p;
   /* 1 if we are scanning insns that could be executed zero times.  */
   int maybe_never = 0;
   /* 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;
-  /* For a rotated loop that is entered near the bottom,
-     this is the label at the top.  Otherwise it is zero.  */
-  rtx loop_top = 0;
   /* Jump insn that enters the loop, or 0 if control drops in.  */
   rtx loop_entry_jump = 0;
-  /* Place in the loop where control enters.  */
-  rtx scan_start;
   /* Number of insns in the loop.  */
   int insn_count;
   int in_libcall = 0;
   int tem;
-  rtx temp;
+  rtx temp, update_start, update_end;
   /* The SET from an insn, if it is the only SET in the insn.  */
   rtx set, set1;
   /* Chain describing insns movable in current loop.  */
@@ -650,7 +626,8 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
   /* Nonzero if we are scanning instructions in a sub-loop.  */
   int loop_depth = 0;
   int nregs;
-  struct loop_info *loop_info = &this_loop_info;
+
+  loop->top = 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
@@ -669,7 +646,7 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
      exit test, the code here to detect that case is very conservative.  */
 
   for (p = NEXT_INSN (loop_start);
-       p != end
+       p != loop_end
         && GET_CODE (p) != CODE_LABEL && GET_RTX_CLASS (GET_CODE (p)) != 'i'
         && (GET_CODE (p) != NOTE
             || (NOTE_LINE_NUMBER (p) != NOTE_INSN_LOOP_BEG
@@ -677,16 +654,16 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
        p = NEXT_INSN (p))
     ;
 
-  scan_start = p;
+  loop->scan_start = p;
 
   /* Set up variables describing this loop.  */
-  prescan_loop (loop_start, end, loop_info);
+  prescan_loop (loop);
   threshold = (loop_info->has_call ? 1 : 2) * (1 + n_non_fixed_regs);
 
   /* If loop has a jump before the first label,
      the true entry is the target of that jump.
      Start scan from there.
-     But record in LOOP_TOP the place where the end-test jumps
+     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)
     {
@@ -701,14 +678,14 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
             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, end))
+         && INSN_IN_RANGE_P (JUMP_LABEL (p), loop_start, loop_end))
        {
-         loop_top = next_label (scan_start);
-         scan_start = JUMP_LABEL (p);
+         loop->top = next_label (loop->scan_start);
+         loop->scan_start = JUMP_LABEL (p);
        }
     }
 
-  /* If SCAN_START was an insn created by loop, we don't know its luid
+  /* If LOOP->SCAN_START was an insn created by loop, we don't know its luid
      as required by loop_reg_used_before_p.  So skip such loops.  (This
      test may never be true, but it's best to play it safe.) 
 
@@ -716,12 +693,12 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
      test also rejects loops starting with a JUMP_INSN that failed the
      test above.  */
 
-  if (INSN_UID (scan_start) >= max_uid_for_loop
-      || GET_CODE (scan_start) != CODE_LABEL)
+  if (INSN_UID (loop->scan_start) >= max_uid_for_loop
+      || GET_CODE (loop->scan_start) != CODE_LABEL)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream, "\nLoop from %d to %d is phony.\n\n",
-                INSN_UID (loop_start), INSN_UID (end));
+                INSN_UID (loop_start), INSN_UID (loop_end));
       return;
     }
 
@@ -740,7 +717,7 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
   VARRAY_CHAR_INIT (may_not_optimize, nregs, "may_not_optimize");
   VARRAY_RTX_INIT (reg_single_usage, nregs, "reg_single_usage");
 
-  count_loop_regs_set (loop_top ? loop_top : loop_start, end,
+  count_loop_regs_set (loop->top ? loop->top : loop->start, loop->end,
                       may_not_optimize, reg_single_usage, &insn_count, nregs);
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
@@ -763,10 +740,10 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
   if (loop_dump_stream)
     {
       fprintf (loop_dump_stream, "\nLoop from %d to %d: %d real insns.\n",
-              INSN_UID (loop_start), INSN_UID (end), insn_count);
-      if (loop_info->cont)
+              INSN_UID (loop_start), INSN_UID (loop_end), insn_count);
+      if (loop->cont)
        fprintf (loop_dump_stream, "Continue at insn %d.\n",
-                INSN_UID (loop_info->cont));
+                INSN_UID (loop->cont));
     }
 
   /* Scan through the loop finding insns that are safe to move.
@@ -782,9 +759,9 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
      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 (scan_start, scan_start, end, loop_top); 
+  for (p = next_insn_in_loop (loop, loop->scan_start); 
        p != NULL_RTX;
-       p = next_insn_in_loop (p, scan_start, end, loop_top))
+       p = next_insn_in_loop (loop, p))
     {
       if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
          && find_reg_note (p, REG_LIBCALL, NULL_RTX))
@@ -850,22 +827,21 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
                      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 (set, p, loop_start,
-                                                 scan_start, end)))
+                      || 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 = invariant_p (src))
+         else if ((tem = loop_invariant_p (loop, src))
                   && (dependencies == 0
-                      || (tem2 = invariant_p (dependencies)) != 0)
+                      || (tem2 = loop_invariant_p (loop, dependencies)) != 0)
                   && (VARRAY_INT (set_in_loop, 
                                   REGNO (SET_DEST (set))) == 1
                       || (tem1
                           = consec_sets_invariant_p 
-                          (SET_DEST (set),
+                          (loop, SET_DEST (set),
                            VARRAY_INT (set_in_loop, REGNO (SET_DEST (set))),
                            p)))
                   /* If the insn can cause a trap (such as divide by zero),
@@ -948,10 +924,12 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
              m->is_equiv = (find_reg_note (p, REG_EQUIV, NULL_RTX) != 0);
              m->savemode = VOIDmode;
              m->regno = regno;
-             /* Set M->cond if either invariant_p or consec_sets_invariant_p
-                returned 2 (only conditionally invariant).  */
+             /* 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 (end)
+             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)]
@@ -1053,7 +1031,7 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
                     assumption.  */
                  m->global = (INSN_UID (p) >= max_uid_for_loop
                               || (uid_luid[REGNO_LAST_UID (regno)]
-                                  > INSN_LUID (end))
+                                  > INSN_LUID (loop_end))
                               || (uid_luid[REGNO_FIRST_UID (regno)]
                                   < INSN_LUID (p))
                               || (labels_in_range_p
@@ -1096,8 +1074,8 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
                  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
-                    && NEXT_INSN (NEXT_INSN (p)) == end
+               && ! (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == loop->top
+                    && NEXT_INSN (NEXT_INSN (p)) == loop_end
                     && simplejump_p (p)))
        maybe_never = 1;
       else if (GET_CODE (p) == NOTE)
@@ -1139,8 +1117,7 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
      optimizing for code size.  */
 
   if (! optimize_size)
-    move_movables (movables, threshold,
-                  insn_count, loop_start, end, nregs);
+    move_movables (loop, movables, threshold, insn_count, nregs);
 
   /* Now candidates that still are negative are those not moved.
      Change set_in_loop to indicate that those are not actually invariant.  */
@@ -1150,15 +1127,25 @@ scan_loop (loop_start, end, loop_cont, unroll_p, bct_p)
 
   /* 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 (scan_start, end, loop_top,
-                                      loop_start, &insn_count);
+  load_mems_and_recount_loop_regs_set (loop, &insn_count);
+
+  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 ();
 
   if (flag_strength_reduce)
     {
       the_movables = movables;
-      strength_reduce (scan_start, end, loop_top,
-                      insn_count, loop_start, end,
-                      loop_info, loop_cont, unroll_p, bct_p);
+      strength_reduce (loop, insn_count, unroll_p, bct_p);
+
+      reg_scan_update (update_start, update_end, loop_max_reg);
+      loop_max_reg = max_reg_num ();
     }
 
   VARRAY_FREE (reg_single_usage);
@@ -1293,8 +1280,12 @@ reg_in_basic_block_p (insn, reg)
        }
     }
 
-  /* The "last use" doesn't follow the "first use"??  */
-  abort ();
+  /* The "last use" that was recorded can't be found after the first
+     use.  This can happen when the last use was deleted while
+     processing an inner loop, this inner loop was then completely
+     unrolled, and the outer loop is always exited after the inner loop,
+     so that everything after the first use becomes a single basic block.  */
+  return 1;
 }
 \f
 /* Compute the benefit of eliminating the insns in the block whose
@@ -1430,7 +1421,7 @@ combine_movables (movables, nregs)
      int nregs;
 {
   register struct movable *m;
-  char *matched_regs = (char *) alloca (nregs);
+  char *matched_regs = (char *) xmalloc (nregs);
   enum machine_mode mode;
 
   /* Regs that are set more than once are not allowed to match
@@ -1533,6 +1524,9 @@ combine_movables (movables, nregs)
          overlap: ;
          }
     }
+
+  /* Clean up.  */
+  free (matched_regs);
 }
 \f
 /* Return 1 if regs X and Y will become the same if moved.  */
@@ -1542,8 +1536,8 @@ regs_match_p (x, y, movables)
      rtx x, y;
      struct movable *movables;
 {
-  int xn = REGNO (x);
-  int yn = REGNO (y);
+  unsigned int xn = REGNO (x);
+  unsigned int yn = REGNO (y);
   struct movable *mx, *my;
 
   for (mx = movables; mx; mx = mx->next)
@@ -1720,25 +1714,23 @@ add_label_notes (x, insns)
    other throughout.  */
 
 static void
-move_movables (movables, threshold, insn_count, loop_start, end, nregs)
+move_movables (loop, movables, threshold, insn_count, nregs)
+     struct loop *loop;
      struct movable *movables;
      int threshold;
      int insn_count;
-     rtx loop_start;
-     rtx end;
      int nregs;
 {
   rtx new_start = 0;
   register struct movable *m;
   register rtx p;
+  rtx loop_start = loop->start;
+  rtx loop_end = loop->end;
   /* Map of pseudo-register replacements to handle combining
      when we move several insns that load the same value
      into different pseudo-registers.  */
-  rtx *reg_map = (rtx *) alloca (nregs * sizeof (rtx));
-  char *already_moved = (char *) alloca (nregs);
-
-  bzero (already_moved, nregs);
-  bzero ((char *) reg_map, nregs * sizeof (rtx));
+  rtx *reg_map = (rtx *) xcalloc (nregs, sizeof (rtx));
+  char *already_moved = (char *) xcalloc (nregs, sizeof (char));
 
   num_movables = 0;
 
@@ -1778,11 +1770,11 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
 
       if (!m->done
          && (! m->cond
-             || (1 == invariant_p (m->set_src)
+             || (1 == loop_invariant_p (loop, m->set_src)
                  && (m->dependencies == 0
-                     || 1 == invariant_p (m->dependencies))
+                     || 1 == loop_invariant_p (loop, m->dependencies))
                  && (m->consec == 0
-                     || 1 == consec_sets_invariant_p (m->set_dest,
+                     || 1 == consec_sets_invariant_p (loop, m->set_dest,
                                                       m->consec + 1,
                                                       m->insn))))
          && (! m->forces || m->forces->done))
@@ -2083,7 +2075,7 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
                             like this as a result of record_jump_cond.  */
                      
                          if ((temp = find_reg_note (i1, REG_EQUAL, NULL_RTX))
-                             && ! invariant_p (XEXP (temp, 0)))
+                             && ! loop_invariant_p (loop, XEXP (temp, 0)))
                            remove_note (i1, temp);
                        }
 
@@ -2144,8 +2136,8 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
                   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 (end))
-               REGNO_LAST_UID (regno) = INSN_UID (end);
+             if (uid_luid[REGNO_LAST_UID (regno)] < INSN_LUID (loop_end))
+               REGNO_LAST_UID (regno) = INSN_UID (loop_end);
 
              /* Combine with this moved insn any other matching movables.  */
 
@@ -2213,7 +2205,7 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
 
   /* Go through all the instructions in the loop, making
      all the register substitutions scheduled in REG_MAP.  */
-  for (p = new_start; p != end; p = NEXT_INSN (p))
+  for (p = new_start; p != loop_end; p = NEXT_INSN (p))
     if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
        || GET_CODE (p) == CALL_INSN)
       {
@@ -2221,6 +2213,10 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
        replace_regs (REG_NOTES (p), reg_map, nregs, 0);
        INSN_CODE (p) = -1;
       }
+
+  /* Clean up.  */
+  free (reg_map);
+  free (already_moved);
 }
 \f
 #if 0
@@ -2277,7 +2273,7 @@ replace_call_address (x, reg, addr)
     {
       if (fmt[i] == 'e')
        replace_call_address (XEXP (x, i), reg, addr);
-      if (fmt[i] == 'E')
+      else if (fmt[i] == 'E')
        {
          register int j;
          for (j = 0; j < XVECLEN (x, i); j++)
@@ -2291,7 +2287,8 @@ replace_call_address (x, reg, addr)
    in the rtx X.  */
 
 static int
-count_nonfixed_reads (x)
+count_nonfixed_reads (loop, x)
+     const struct loop *loop;
      rtx x;
 {
   register enum rtx_code code;
@@ -2316,8 +2313,8 @@ count_nonfixed_reads (x)
       return 0;
 
     case MEM:
-      return ((invariant_p (XEXP (x, 0)) != 1)
-             + count_nonfixed_reads (XEXP (x, 0)));
+      return ((loop_invariant_p (loop, XEXP (x, 0)) != 1)
+             + count_nonfixed_reads (loop, XEXP (x, 0)));
       
     default:
       break;
@@ -2328,12 +2325,12 @@ count_nonfixed_reads (x)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       value += count_nonfixed_reads (XEXP (x, i));
+       value += count_nonfixed_reads (loop, XEXP (x, i));
       if (fmt[i] == 'E')
        {
          register int j;
          for (j = 0; j < XVECLEN (x, i); j++)
-           value += count_nonfixed_reads (XVECEXP (x, i, j));
+           value += count_nonfixed_reads (loop, XVECEXP (x, i, j));
        }
     }
   return value;
@@ -2383,35 +2380,37 @@ constant_high_bytes (p, loop_start)
 #endif
 \f
 /* Scan a loop setting the elements `cont', `vtop', `loops_enclosed',
-   `has_call', `has_volatile', and `has_tablejump' within LOOP_INFO.
-   Set the global variables `unknown_address_altered' and
-   `num_mem_sets'.  Also, fill in the array `loop_mems' and the list
-   `loop_store_mems'.  */
+   `has_call', `has_volatile', and `has_tablejump' within LOOP.
+   Set the global variables `unknown_address_altered',
+   `unknown_constant_address_altered', and `num_mem_sets'.  Also, fill
+   in the array `loop_mems' and the list `loop_store_mems'.  */
 
 static void
-prescan_loop (start, end, loop_info)
-     rtx start, end;
-     struct loop_info *loop_info;
+prescan_loop (loop)
+     struct loop *loop;
 {
   register int level = 1;
   rtx insn;
+  struct loop_info *loop_info = LOOP_INFO (loop);
+  rtx start = loop->start;
+  rtx end = loop->end;
   /* The label after END.  Jumping here is just like falling off the
      end of the loop.  We use next_nonnote_insn instead of next_label
      as a hedge against the (pathological) case where some actual insn
      might end up between the two.  */
   rtx exit_target = next_nonnote_insn (end);
 
-  loop_info->num = uid_loop_num [INSN_UID (start)];
   loop_info->has_indirect_jump = indirect_jump_in_function;
   loop_info->has_call = 0;
   loop_info->has_volatile = 0;
   loop_info->has_tablejump = 0;
-  loop_info->loops_enclosed = 1;
   loop_info->has_multiple_exit_targets = 0;
-  loop_info->cont = 0;
-  loop_info->vtop = 0;
+  loop->cont = 0;
+  loop->vtop = 0;
+  loop->level = 1;
 
   unknown_address_altered = 0;
+  unknown_constant_address_altered = 0;
   loop_store_mems = NULL_RTX;
   first_loop_store_insn = NULL_RTX;
   loop_mems_idx = 0;
@@ -2426,7 +2425,7 @@ prescan_loop (start, end, loop_info)
            {
              ++level;
              /* Count number of loops contained in this one.  */
-             loop_info->loops_enclosed++;
+             loop->level++;
            }
          else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
            {
@@ -2440,7 +2439,7 @@ prescan_loop (start, end, loop_info)
          else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT)
            {
              if (level == 1)
-               loop_info->cont = insn;
+               loop->cont = insn;
            }
          else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_VTOP)
            {
@@ -2449,7 +2448,7 @@ prescan_loop (start, end, loop_info)
                 start.  Thus, we can assume that the loop condition
                 was true when the loop was entered.  */
              if (level == 1)
-               loop_info->vtop = insn;
+               loop->vtop = insn;
            }
        }
       else if (GET_CODE (insn) == CALL_INSN)
@@ -2471,7 +2470,7 @@ prescan_loop (start, end, loop_info)
                  || GET_CODE (PATTERN (insn)) == ADDR_VEC))
            loop_info->has_tablejump = 1;
          
-         note_stores (PATTERN (insn), note_addr_stored);
+         note_stores (PATTERN (insn), note_addr_stored, NULL);
          if (! first_loop_store_insn && loop_store_mems)
            first_loop_store_insn = insn;
 
@@ -2519,48 +2518,47 @@ prescan_loop (start, end, loop_info)
 
   /* Now, rescan the loop, setting up the LOOP_MEMS array.  */
   if (/* We can't tell what MEMs are aliased by what.  */
-      !unknown_address_altered 
+      ! unknown_address_altered 
       /* An exception thrown by a called function might land us
         anywhere.  */
-      && !loop_info->has_call
+      && ! loop_info->has_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
         require actual function calls.  */
-      && !current_function_calls_alloca
+      && ! current_function_calls_alloca
       /* There are ways to leave the loop other than falling off the
         end.  */
-      && !loop_info->has_multiple_exit_targets)
+      && ! loop_info->has_multiple_exit_targets)
     for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
         insn = NEXT_INSN (insn))
       for_each_rtx (&insn, insert_loop_mem, 0);
 }
 \f
-/* LOOP_NUMBER_CONT_DOMINATOR is now the last label between the loop start
+/* 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_NUMBER_CONT_DOMINATOR that has a
-   target between LOOP_DOMINATOR and the continue note, move
-   LOOP_NUMBER_CONT_DOMINATOR forward to that label; if a jump's
-   destination cannot be determined, clear LOOP_NUMBER_CONT_DOMINATOR.  */
+   and what we have so far as LOOP->CONT_DOMINATOR that has a
+   target between LOOP->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.  */
 
 static void
-verify_dominator (loop_number)
-     int loop_number;
+verify_dominator (loop)
+     struct loop *loop;
 {
   rtx insn;
 
-  if (! loop_number_cont_dominator[loop_number])
+  if (! loop->cont_dominator)
     /* This can happen for an empty loop, e.g. in
        gcc.c-torture/compile/920410-2.c  */
     return;
-  if (loop_number_cont_dominator[loop_number] == const0_rtx)
+  if (loop->cont_dominator == const0_rtx)
     {
-      loop_number_cont_dominator[loop_number] = 0;
+      loop->cont_dominator = 0;
       return;
     }
-  for (insn = loop_number_loop_starts[loop_number];
-       insn != loop_number_cont_dominator[loop_number];
+  for (insn = loop->start; insn != loop->cont_dominator;
        insn = NEXT_INSN (insn))
     {
       if (GET_CODE (insn) == JUMP_INSN
@@ -2572,20 +2570,20 @@ verify_dominator (loop_number)
          /* 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_NUMBER_CONT_DOMINATOR.  */
+            LOOP->CONT_DOMINATOR.  */
          if ((! condjump_p (insn)
               && ! condjump_in_parallel_p (insn))
              || label == NULL_RTX)
            {
-             loop_number_cont_dominator[loop_number] = NULL_RTX;
+             loop->cont_dominator = NULL_RTX;
              return;
            }
 
          label_luid = INSN_LUID (label);
-         if (label_luid < INSN_LUID (loop_number_loop_cont[loop_number])
+         if (label_luid < INSN_LUID (loop->cont)
              && (label_luid
-                 > INSN_LUID (loop_number_cont_dominator[loop_number])))
-           loop_number_cont_dominator[loop_number] = label;
+                 > INSN_LUID (loop->cont)))
+           loop->cont_dominator = label;
        }
     }
 }
@@ -2595,115 +2593,116 @@ verify_dominator (loop_number)
    to from outside the loop.  */
 
 static void
-find_and_verify_loops (f)
+find_and_verify_loops (f, loops)
      rtx f;
+     struct loops *loops;
 {
-  rtx insn, label;
-  int current_loop = -1;
-  int next_loop = -1;
-  int loop;
+  rtx insn;
+  rtx label;
+  int num_loops;
+  struct loop *current_loop;
+  struct loop *next_loop;
+  struct loop *loop;
+
+  num_loops = loops->num;
 
   compute_luids (f, NULL_RTX, 0);
 
   /* If there are jumps to undefined labels,
      treat them as jumps out of any/all loops.
      This also avoids writing past end of tables when there are no loops.  */
-  uid_loop_num[0] = -1;
+  uid_loop[0] = NULL;
 
   /* Find boundaries of loops, mark which loops are contained within
      loops, and invalidate loops that have setjmp.  */
 
+  num_loops = 0;
+  current_loop = NULL;
   for (insn = f; insn; insn = NEXT_INSN (insn))
     {
       if (GET_CODE (insn) == NOTE)
        switch (NOTE_LINE_NUMBER (insn))
          {
          case NOTE_INSN_LOOP_BEG:
-           loop_number_loop_starts[++next_loop] =  insn;
-           loop_number_loop_ends[next_loop] = 0;
-           loop_number_loop_cont[next_loop] = 0;
-           loop_number_cont_dominator[next_loop] = 0;
-           loop_outer_loop[next_loop] = current_loop;
-           loop_invalid[next_loop] = 0;
-           loop_number_exit_labels[next_loop] = 0;
-           loop_number_exit_count[next_loop] = 0;
+           next_loop = loops->array + num_loops;
+           next_loop->num = num_loops;
+           num_loops++;
+           next_loop->start = insn;
+           next_loop->outer = current_loop;
            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 != -1; loop = loop_outer_loop[loop])
+           for (loop = current_loop; loop; loop = loop->outer)
              {
-               loop_invalid[loop] = 1;
+               loop->invalid = 1;
                if (loop_dump_stream)
                  fprintf (loop_dump_stream,
                           "\nLoop at %d ignored due to setjmp.\n",
-                          INSN_UID (loop_number_loop_starts[loop]));
+                          INSN_UID (loop->start));
              }
            break;
 
          case NOTE_INSN_LOOP_CONT:
-           loop_number_loop_cont[current_loop] = insn;
+           current_loop->cont = insn;
            break;
          case NOTE_INSN_LOOP_END:
-           if (current_loop == -1)
+           if (! current_loop)
              abort ();
 
-           loop_number_loop_ends[current_loop] = insn;
+           current_loop->end = insn;
            verify_dominator (current_loop);
-           current_loop = loop_outer_loop[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_number_loop_dominator.  */
+        and NOTE_INSN_LOOP_END notes, update loop->dominator.  */
       else if (GET_CODE (insn) == JUMP_INSN
               && GET_CODE (PATTERN (insn)) != RETURN
-              && current_loop >= 0)
+              && current_loop)
        {
-         int this_loop_num;
          rtx label = JUMP_LABEL (insn);
 
          if (! condjump_p (insn) && ! condjump_in_parallel_p (insn))
            label = NULL_RTX;
 
-         this_loop_num = current_loop;
+         loop = current_loop;
          do
            {
              /* First see if we care about this loop.  */
-             if (loop_number_loop_cont[this_loop_num]
-                 && loop_number_cont_dominator[this_loop_num] != const0_rtx)
+             if (loop->cont && loop->cont_dominator != const0_rtx)
                {
                  /* If the jump destination is not known, invalidate
-                    loop_number_const_dominator.  */
+                    loop->const_dominator.  */
                  if (! label)
-                   loop_number_cont_dominator[this_loop_num] = const0_rtx;
+                   loop->cont_dominator = const0_rtx;
                  else
                    /* Check if the destination is between loop start and
                       cont.  */
                    if ((INSN_LUID (label)
-                        < INSN_LUID (loop_number_loop_cont[this_loop_num]))
+                        < INSN_LUID (loop->cont))
                        && (INSN_LUID (label)
-                           > INSN_LUID (loop_number_loop_starts[this_loop_num]))
+                           > INSN_LUID (loop->start))
                        /* And if there is no later destination already
                           recorded.  */
-                       && (! loop_number_cont_dominator[this_loop_num]
+                       && (! loop->cont_dominator
                            || (INSN_LUID (label)
-                               > INSN_LUID (loop_number_cont_dominator
-                                            [this_loop_num]))))
-                     loop_number_cont_dominator[this_loop_num] = label;
+                               > INSN_LUID (loop->cont_dominator))))
+                     loop->cont_dominator = label;
                }
-             this_loop_num = loop_outer_loop[this_loop_num];
+             loop = loop->outer;
            }
-         while (this_loop_num >= 0);
+         while (loop);
        }
 
       /* Note that this will mark the NOTE_INSN_LOOP_END note as being in the
         enclosing loop, but this doesn't matter.  */
-      uid_loop_num[INSN_UID (insn)] = current_loop;
+      uid_loop[INSN_UID (insn)] = current_loop;
     }
 
   /* Any loop containing a label used in an initializer must be invalidated,
@@ -2711,12 +2710,9 @@ find_and_verify_loops (f)
 
   for (label = forced_labels; label; label = XEXP (label, 1))
     {
-      int loop_num;
-
-      for (loop_num = uid_loop_num[INSN_UID (XEXP (label, 0))];
-          loop_num != -1;
-          loop_num = loop_outer_loop[loop_num])
-       loop_invalid[loop_num] = 1;
+      for (loop = uid_loop[INSN_UID (XEXP (label, 0))];
+          loop; loop = loop->outer)
+       loop->invalid = 1;
     }
 
   /* Any loop containing a label used for an exception handler must be
@@ -2724,12 +2720,9 @@ find_and_verify_loops (f)
 
   for (label = exception_handler_labels; label; label = XEXP (label, 1))
     {
-      int loop_num;
-
-      for (loop_num = uid_loop_num[INSN_UID (XEXP (label, 0))];
-          loop_num != -1;
-          loop_num = loop_outer_loop[loop_num])
-       loop_invalid[loop_num] = 1;
+      for (loop = uid_loop[INSN_UID (XEXP (label, 0))];
+          loop; loop = loop->outer)
+       loop->invalid = 1;
     }
 
   /* Now scan all insn's in the function.  If any JUMP_INSN branches into a
@@ -2748,40 +2741,37 @@ find_and_verify_loops (f)
   for (insn = f; insn; insn = NEXT_INSN (insn))
     if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
       {
-       int this_loop_num = uid_loop_num[INSN_UID (insn)];
+       struct loop *this_loop = uid_loop[INSN_UID (insn)];
 
        if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
          {
            rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
            if (note)
              {
-               int loop_num;
-
-               for (loop_num = uid_loop_num[INSN_UID (XEXP (note, 0))];
-                    loop_num != -1;
-                    loop_num = loop_outer_loop[loop_num])
-                 loop_invalid[loop_num] = 1;
+               for (loop = uid_loop[INSN_UID (XEXP (note, 0))];
+                    loop; loop = loop->outer)
+                 loop->invalid = 1;
              }
          }
 
        if (GET_CODE (insn) != JUMP_INSN)
          continue;
 
-       mark_loop_jump (PATTERN (insn), this_loop_num);
+       mark_loop_jump (PATTERN (insn), this_loop);
 
        /* See if this is an unconditional branch outside the loop.  */
-       if (this_loop_num != -1
+       if (this_loop
            && (GET_CODE (PATTERN (insn)) == RETURN
                || (simplejump_p (insn)
-                   && (uid_loop_num[INSN_UID (JUMP_LABEL (insn))]
-                       != this_loop_num)))
+                   && (uid_loop[INSN_UID (JUMP_LABEL (insn))]
+                       != this_loop)))
            && get_max_uid () < max_uid_for_loop)
          {
            rtx p;
            rtx our_next = next_real_insn (insn);
            rtx last_insn_to_move = NEXT_INSN (insn);
-           int dest_loop;
-           int outer_loop = -1;
+           struct loop *dest_loop;
+           struct loop *outer_loop = NULL;
 
            /* Go backwards until we reach the start of the loop, a label,
               or a JUMP_INSN.  */
@@ -2798,12 +2788,12 @@ find_and_verify_loops (f)
 
            if (JUMP_LABEL (insn))
              {
-               dest_loop = uid_loop_num[INSN_UID (JUMP_LABEL (insn))];
-               if (dest_loop != -1)
+               dest_loop = uid_loop[INSN_UID (JUMP_LABEL (insn))];
+               if (dest_loop)
                  {
-                   for (outer_loop = dest_loop; outer_loop != -1;
-                        outer_loop = loop_outer_loop[outer_loop])
-                     if (outer_loop == this_loop_num)
+                   for (outer_loop = dest_loop; outer_loop;
+                        outer_loop = outer_loop->outer)
+                     if (outer_loop == this_loop)
                        break;
                  }
              }
@@ -2811,8 +2801,8 @@ find_and_verify_loops (f)
            /* Make sure that the target of P is within the current loop.  */
 
            if (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p)
-               && uid_loop_num[INSN_UID (JUMP_LABEL (p))] != this_loop_num)
-             outer_loop = this_loop_num;
+               && uid_loop[INSN_UID (JUMP_LABEL (p))] != this_loop)
+             outer_loop = this_loop;
 
            /* If we stopped on a JUMP_INSN to the next insn after INSN,
               we have a block of code to try to move.
@@ -2823,7 +2813,7 @@ find_and_verify_loops (f)
               of the block, invert the jump in P and point it to that label,
               and move the block of code to the spot we found.  */
 
-           if (outer_loop == -1
+           if (! outer_loop
                && GET_CODE (p) == JUMP_INSN
                && JUMP_LABEL (p) != 0
                /* Just ignore jumps to labels that were never emitted.
@@ -2839,18 +2829,32 @@ find_and_verify_loops (f)
              {
                rtx target
                  = JUMP_LABEL (insn) ? JUMP_LABEL (insn) : get_last_insn ();
-               int target_loop_num = uid_loop_num[INSN_UID (target)];
-               rtx loc;
+               struct loop *target_loop = uid_loop[INSN_UID (target)];
+               rtx loc, loc2;
 
                for (loc = target; loc; loc = PREV_INSN (loc))
                  if (GET_CODE (loc) == BARRIER
-                     && uid_loop_num[INSN_UID (loc)] == target_loop_num)
+                     /* Don't move things inside a tablejump.  */
+                     && ((loc2 = next_nonnote_insn (loc)) == 0
+                         || GET_CODE (loc2) != CODE_LABEL
+                         || (loc2 = next_nonnote_insn (loc2)) == 0
+                         || GET_CODE (loc2) != JUMP_INSN
+                         || (GET_CODE (PATTERN (loc2)) != ADDR_VEC
+                             && GET_CODE (PATTERN (loc2)) != ADDR_DIFF_VEC))
+                     && uid_loop[INSN_UID (loc)] == target_loop)
                    break;
 
                if (loc == 0)
                  for (loc = target; loc; loc = NEXT_INSN (loc))
                    if (GET_CODE (loc) == BARRIER
-                       && uid_loop_num[INSN_UID (loc)] == target_loop_num)
+                       /* Don't move things inside a tablejump.  */
+                       && ((loc2 = next_nonnote_insn (loc)) == 0
+                           || GET_CODE (loc2) != CODE_LABEL
+                           || (loc2 = next_nonnote_insn (loc2)) == 0
+                           || GET_CODE (loc2) != JUMP_INSN
+                           || (GET_CODE (PATTERN (loc2)) != ADDR_VEC
+                               && GET_CODE (PATTERN (loc2)) != ADDR_DIFF_VEC))
+                       && uid_loop[INSN_UID (loc)] == target_loop)
                      break;
 
                if (loc)
@@ -2861,7 +2865,7 @@ find_and_verify_loops (f)
                    /* Ensure our label doesn't go away.  */
                    LABEL_NUSES (cond_label)++;
 
-                   /* Verify that uid_loop_num is large enough and that
+                   /* Verify that uid_loop is large enough and that
                       we can invert P.  */
                   if (invert_jump (p, new_label))
                     {
@@ -2894,23 +2898,21 @@ find_and_verify_loops (f)
                                                  last_insn_to_move);
                       reorder_insns (new_label, last_insn_to_move, loc);
 
-                      /* All those insns are now in TARGET_LOOP_NUM.  */
+                      /* All those insns are now in TARGET_LOOP.  */
                       for (q = new_label; 
                            q != NEXT_INSN (last_insn_to_move);
                            q = NEXT_INSN (q))
-                        uid_loop_num[INSN_UID (q)] = target_loop_num;
+                        uid_loop[INSN_UID (q)] = target_loop;
 
                       /* The label jumped to by INSN is no longer a loop exit.
                          Unless INSN does not have a label (e.g., it is a
-                         RETURN insn), search loop_number_exit_labels to find
+                         RETURN insn), search loop->exit_labels to find
                          its label_ref, and remove it.  Also turn off
                          LABEL_OUTSIDE_LOOP_P bit.  */
                       if (JUMP_LABEL (insn))
                         {
-                          int loop_num;
-
                           for (q = 0,
-                               r = loop_number_exit_labels[this_loop_num];
+                               r = this_loop->exit_labels;
                                r; q = r, r = LABEL_NEXTREF (r))
                             if (XEXP (r, 0) == JUMP_LABEL (insn))
                               {
@@ -2918,26 +2920,25 @@ find_and_verify_loops (f)
                                 if (q)
                                   LABEL_NEXTREF (q) = LABEL_NEXTREF (r);
                                 else
-                                  loop_number_exit_labels[this_loop_num]
-                                    = LABEL_NEXTREF (r);
+                                  this_loop->exit_labels = LABEL_NEXTREF (r);
                                 break;
                               }
 
-                          for (loop_num = this_loop_num;
-                               loop_num != -1 && loop_num != target_loop_num;
-                               loop_num = loop_outer_loop[loop_num])
-                            loop_number_exit_count[loop_num]--;
+                          for (loop = this_loop; loop && loop != target_loop;
+                               loop = loop->outer)
+                            loop->exit_count--;
 
-                          /* If we didn't find it, then something is wrong.  */
+                          /* If we didn't find it, then something is
+                              wrong.  */
                           if (! r)
                             abort ();
                         }
 
                       /* P is now a jump outside the loop, so it must be put
-                         in loop_number_exit_labels, and marked as such.
+                         in loop->exit_labels, and marked as such.
                          The easiest way to do this is to just call
                          mark_loop_jump again for P.  */
-                      mark_loop_jump (PATTERN (p), this_loop_num);
+                      mark_loop_jump (PATTERN (p), this_loop);
 
                       /* If INSN now jumps to the insn after it,
                          delete INSN.  */
@@ -2970,12 +2971,12 @@ find_and_verify_loops (f)
    For speed, we assume that X is part of a pattern of a JUMP_INSN.  */
 
 static void
-mark_loop_jump (x, loop_num)
+mark_loop_jump (x, loop)
      rtx x;
-     int loop_num;
+     struct loop *loop;
 {
-  int dest_loop;
-  int outer_loop;
+  struct loop *dest_loop;
+  struct loop *outer_loop;
   int i;
 
   switch (GET_CODE (x))
@@ -2992,28 +2993,28 @@ mark_loop_jump (x, loop_num)
 
     case CONST:
       /* There could be a label reference in here.  */
-      mark_loop_jump (XEXP (x, 0), loop_num);
+      mark_loop_jump (XEXP (x, 0), loop);
       return;
 
     case PLUS:
     case MINUS:
     case MULT:
-      mark_loop_jump (XEXP (x, 0), loop_num);
-      mark_loop_jump (XEXP (x, 1), loop_num);
+      mark_loop_jump (XEXP (x, 0), loop);
+      mark_loop_jump (XEXP (x, 1), loop);
       return;
 
     case LO_SUM:
       /* This may refer to a LABEL_REF or SYMBOL_REF.  */
-      mark_loop_jump (XEXP (x, 1), loop_num);
+      mark_loop_jump (XEXP (x, 1), loop);
       return;
 
     case SIGN_EXTEND:
     case ZERO_EXTEND:
-      mark_loop_jump (XEXP (x, 0), loop_num);
+      mark_loop_jump (XEXP (x, 0), loop);
       return;
 
     case LABEL_REF:
-      dest_loop = uid_loop_num[INSN_UID (XEXP (x, 0))];
+      dest_loop = uid_loop[INSN_UID (XEXP (x, 0))];
 
       /* Link together all labels that branch outside the loop.  This
         is used by final_[bg]iv_value and the loop unrolling code.  Also
@@ -3022,75 +3023,74 @@ mark_loop_jump (x, loop_num)
 
       /* A check to make sure the label is not in an inner nested loop,
         since this does not count as a loop exit.  */
-      if (dest_loop != -1)
+      if (dest_loop)
        {
-         for (outer_loop = dest_loop; outer_loop != -1;
-              outer_loop = loop_outer_loop[outer_loop])
-           if (outer_loop == loop_num)
+         for (outer_loop = dest_loop; outer_loop;
+              outer_loop = outer_loop->outer)
+           if (outer_loop == loop)
              break;
        }
       else
-       outer_loop = -1;
+       outer_loop = NULL;
 
-      if (loop_num != -1 && outer_loop == -1)
+      if (loop && ! outer_loop)
        {
          LABEL_OUTSIDE_LOOP_P (x) = 1;
-         LABEL_NEXTREF (x) = loop_number_exit_labels[loop_num];
-         loop_number_exit_labels[loop_num] = x;
+         LABEL_NEXTREF (x) = loop->exit_labels;
+         loop->exit_labels = x;
 
-         for (outer_loop = loop_num;
-              outer_loop != -1 && outer_loop != dest_loop;
-              outer_loop = loop_outer_loop[outer_loop])
-           loop_number_exit_count[outer_loop]++;
+         for (outer_loop = loop;
+              outer_loop && outer_loop != dest_loop;
+              outer_loop = outer_loop->outer)
+           outer_loop->exit_count++;
        }
 
       /* If this is inside a loop, but not in the current loop or one enclosed
         by it, it invalidates at least one loop.  */
 
-      if (dest_loop == -1)
+      if (! dest_loop)
        return;
 
       /* We must invalidate every nested loop containing the target of this
         label, except those that also contain the jump insn.  */
 
-      for (; dest_loop != -1; dest_loop = loop_outer_loop[dest_loop])
+      for (; dest_loop; dest_loop = dest_loop->outer)
        {
          /* Stop when we reach a loop that also contains the jump insn.  */
-         for (outer_loop = loop_num; outer_loop != -1;
-              outer_loop = loop_outer_loop[outer_loop])
+         for (outer_loop = loop; outer_loop; outer_loop = outer_loop->outer)
            if (dest_loop == outer_loop)
              return;
 
          /* If we get here, we know we need to invalidate a loop.  */
-         if (loop_dump_stream && ! loop_invalid[dest_loop])
+         if (loop_dump_stream && ! dest_loop->invalid)
            fprintf (loop_dump_stream,
                     "\nLoop at %d ignored due to multiple entry points.\n",
-                    INSN_UID (loop_number_loop_starts[dest_loop]));
+                    INSN_UID (dest_loop->start));
          
-         loop_invalid[dest_loop] = 1;
+         dest_loop->invalid = 1;
        }
       return;
 
     case SET:
       /* If this is not setting pc, ignore.  */
       if (SET_DEST (x) == pc_rtx)
-       mark_loop_jump (SET_SRC (x), loop_num);
+       mark_loop_jump (SET_SRC (x), loop);
       return;
 
     case IF_THEN_ELSE:
-      mark_loop_jump (XEXP (x, 1), loop_num);
-      mark_loop_jump (XEXP (x, 2), loop_num);
+      mark_loop_jump (XEXP (x, 1), loop);
+      mark_loop_jump (XEXP (x, 2), loop);
       return;
 
     case PARALLEL:
     case ADDR_VEC:
       for (i = 0; i < XVECLEN (x, 0); i++)
-       mark_loop_jump (XVECEXP (x, 0, i), loop_num);
+       mark_loop_jump (XVECEXP (x, 0, i), loop);
       return;
 
     case ADDR_DIFF_VEC:
       for (i = 0; i < XVECLEN (x, 1); i++)
-       mark_loop_jump (XVECEXP (x, 1, i), loop_num);
+       mark_loop_jump (XVECEXP (x, 1, i), loop);
       return;
 
     default:
@@ -3098,16 +3098,15 @@ mark_loop_jump (x, loop_num)
         jump out of the loop.  However, we have no way to link the destination
         of this jump onto the list of exit labels.  To be safe we mark this
         loop and any containing loops as invalid.  */
-      if (loop_num != -1)
+      if (loop)
        {
-         for (outer_loop = loop_num; outer_loop != -1;
-              outer_loop = loop_outer_loop[outer_loop])
+         for (outer_loop = loop; outer_loop; outer_loop = outer_loop->outer)
            {
-             if (loop_dump_stream && ! loop_invalid[outer_loop])
+             if (loop_dump_stream && ! outer_loop->invalid)
                fprintf (loop_dump_stream,
                         "\nLoop at %d ignored due to unknown exit jump.\n",
-                        INSN_UID (loop_number_loop_starts[outer_loop]));
-             loop_invalid[outer_loop] = 1;
+                        INSN_UID (outer_loop->start));
+             outer_loop->invalid = 1;
            }
        }
       return;
@@ -3137,9 +3136,10 @@ labels_in_range_p (insn, end)
 /* Record that a memory reference X is being set.  */
 
 static void
-note_addr_stored (x, y)
+note_addr_stored (x, y, data)
      rtx x;
      rtx y ATTRIBUTE_UNUSED;
+     void *data ATTRIBUTE_UNUSED;
 {
   if (x == 0 || GET_CODE (x) != MEM)
     return;
@@ -3149,14 +3149,50 @@ note_addr_stored (x, y)
   num_mem_sets++;
 
   /* BLKmode MEM means all memory is clobbered.  */
-  if (GET_MODE (x) == BLKmode)
-    unknown_address_altered = 1;
+    if (GET_MODE (x) == BLKmode)
+    {
+      if (RTX_UNCHANGING_P (x))
+       unknown_constant_address_altered = 1;
+      else
+       unknown_address_altered = 1;
 
-  if (unknown_address_altered)
-    return;
+      return;
+    }
 
   loop_store_mems = gen_rtx_EXPR_LIST (VOIDmode, x, loop_store_mems);
 }
+
+/* X is a value modified by an INSN that references a biv inside a loop
+   exit test (ie, X is somehow related to the value of the biv).  If X
+   is a pseudo that is used more than once, then the biv is (effectively)
+   used more than once.  DATA is really an `int *', and is set if the
+   biv is used more than once.  */
+
+static void
+note_set_pseudo_multiple_uses (x, y, data)
+     rtx x;
+     rtx y ATTRIBUTE_UNUSED;
+     void *data;
+{
+  if (x == 0)
+    return;
+
+  while (GET_CODE (x) == STRICT_LOW_PART
+        || GET_CODE (x) == SIGN_EXTRACT
+        || GET_CODE (x) == ZERO_EXTRACT
+        || GET_CODE (x) == SUBREG)
+    x = XEXP (x, 0);
+
+  if (GET_CODE (x) != REG || REGNO (x) < FIRST_PSEUDO_REGISTER)
+    return;
+
+  /* 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 (reg_single_usage, REGNO (x))
+      || VARRAY_RTX (reg_single_usage, REGNO (x)) == const0_rtx)
+    *((int *) data) = 1;
+}
 \f
 /* Return nonzero if the rtx X is invariant over the current loop.
 
@@ -3167,7 +3203,8 @@ note_addr_stored (x, y)
    anything stored in `loop_store_mems'.  */
 
 int
-invariant_p (x)
+loop_invariant_p (loop, x)
+     const struct loop *loop;
      register rtx x;
 {
   register int i;
@@ -3216,7 +3253,7 @@ invariant_p (x)
          && ! current_function_has_nonlocal_goto)
        return 1;
 
-      if (this_loop_info.has_call
+      if (LOOP_INFO (loop)->has_call
          && REGNO (x) < FIRST_PSEUDO_REGISTER && call_used_regs[REGNO (x)])
        return 0;
 
@@ -3232,14 +3269,12 @@ invariant_p (x)
       if (MEM_VOLATILE_P (x))
        return 0;
 
-      /* Read-only items (such as constants in a constant pool) are
-        invariant if their address is.  */
-      if (RTX_UNCHANGING_P (x))
-       break;
-
-      /* If we had a subroutine call, any location in memory could have been
-        clobbered.  */
-      if (unknown_address_altered)
+      /* If we had a subroutine call, any location in memory could
+        have been clobbered.  We used to test here for volatile and
+        readonly, but true_dependence knows how to do that better
+        than we do. */
+      if (RTX_UNCHANGING_P (x)
+         ? unknown_constant_address_altered : unknown_address_altered)
        return 0;
 
       /* See if there is any dependence between a store and this load.  */
@@ -3249,6 +3284,7 @@ invariant_p (x)
          if (true_dependence (XEXP (mem_list_entry, 0), VOIDmode,
                               x, rtx_varies_p))
            return 0;
+
          mem_list_entry = XEXP (mem_list_entry, 1);
        }
 
@@ -3271,7 +3307,7 @@ invariant_p (x)
     {
       if (fmt[i] == 'e')
        {
-         int tem = invariant_p (XEXP (x, i));
+         int tem = loop_invariant_p (loop, XEXP (x, i));
          if (tem == 0)
            return 0;
          if (tem == 2)
@@ -3282,7 +3318,7 @@ invariant_p (x)
          register int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            {
-             int tem = invariant_p (XVECEXP (x, i, j));
+             int tem = loop_invariant_p (loop, XVECEXP (x, i, j));
              if (tem == 0)
                return 0;
              if (tem == 2)
@@ -3307,12 +3343,13 @@ invariant_p (x)
    and that its source is invariant.  */
 
 static int
-consec_sets_invariant_p (reg, n_sets, insn)
+consec_sets_invariant_p (loop, reg, n_sets, insn)
+     const struct loop *loop;
      int n_sets;
      rtx reg, insn;
 {
-  register rtx p = insn;
-  register int regno = REGNO (reg);
+  rtx p = insn;
+  unsigned int regno = REGNO (reg);
   rtx temp;
   /* Number of sets we have to insist on finding after INSN.  */
   int count = n_sets - 1;
@@ -3344,7 +3381,7 @@ consec_sets_invariant_p (reg, n_sets, insn)
          && GET_CODE (SET_DEST (set)) == REG
          && REGNO (SET_DEST (set)) == regno)
        {
-         this = invariant_p (SET_SRC (set));
+         this = loop_invariant_p (loop, SET_SRC (set));
          if (this != 0)
            value |= this;
          else if ((temp = find_reg_note (p, REG_EQUAL, NULL_RTX)))
@@ -3354,7 +3391,7 @@ consec_sets_invariant_p (reg, n_sets, insn)
                 notes are OK.  */
              this = (CONSTANT_P (XEXP (temp, 0))
                      || (find_reg_note (p, REG_RETVAL, NULL_RTX)
-                         && invariant_p (XEXP (temp, 0))));
+                         && loop_invariant_p (loop, XEXP (temp, 0))));
              if (this != 0)
                value |= this;
            }
@@ -3369,7 +3406,7 @@ consec_sets_invariant_p (reg, n_sets, insn)
     }
 
   VARRAY_INT (set_in_loop, regno) = old;
-  /* If invariant_p ever returned 2, we return 2.  */
+  /* If loop_invariant_p ever returned 2, we return 2.  */
   return 1 + (value & 2);
 }
 
@@ -3399,7 +3436,7 @@ all_sets_invariant_p (reg, insn, table)
          && GET_CODE (SET_DEST (PATTERN (p))) == REG
          && REGNO (SET_DEST (PATTERN (p))) == regno)
        {
-         if (!invariant_p (SET_SRC (PATTERN (p)), table))
+         if (! loop_invariant_p (loop, SET_SRC (PATTERN (p)), table))
            return 0;
        }
     }
@@ -3516,11 +3553,10 @@ count_loop_regs_set (from, to, may_not_move, single_usage, count_ptr, nregs)
      int *count_ptr;
      int nregs;
 {
-  register rtx *last_set = (rtx *) alloca (nregs * sizeof (rtx));
+  register rtx *last_set = (rtx *) xcalloc (nregs, sizeof (rtx));
   register rtx insn;
   register int count = 0;
 
-  bzero ((char *) last_set, nregs * sizeof (rtx));
   for (insn = from; insn != to; insn = NEXT_INSN (insn))
     {
       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
@@ -3550,35 +3586,38 @@ count_loop_regs_set (from, to, may_not_move, single_usage, count_ptr, nregs)
        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 is entered at SCAN_START,
-   return 1 if the register set in SET contained in insn INSN is used by
-   any insn that precedes INSN in cyclic order starting
-   from the loop entry point.
+/* Given a loop that is bounded by LOOP->START and LOOP->END and that
+   is entered at LOOP->SCAN_START, return 1 if the register set in SET
+   contained in insn INSN is used by any insn that precedes INSN in
+   cyclic order starting from the loop entry point.
 
    We don't want to use INSN_LUID here because if we restrict INSN to those
    that have a valid INSN_LUID, it means we cannot move an invariant out
    from an inner loop past two loops.  */
 
 static int
-loop_reg_used_before_p (set, insn, loop_start, scan_start, loop_end)
-     rtx set, insn, loop_start, scan_start, loop_end;
+loop_reg_used_before_p (loop, set, insn)
+     const struct loop *loop;
+     rtx set, insn;
 {
   rtx reg = SET_DEST (set);
   rtx p;
 
   /* Scan forward checking for register usage.  If we hit INSN, we
-     are done.  Otherwise, if we hit LOOP_END, wrap around to LOOP_START.  */
-  for (p = scan_start; p != insn; p = NEXT_INSN (p))
+     are done.  Otherwise, if we hit LOOP->END, wrap around to LOOP->START.  */
+  for (p = loop->scan_start; p != insn; p = NEXT_INSN (p))
     {
       if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
          && reg_overlap_mentioned_p (reg, PATTERN (p)))
        return 1;
 
-      if (p == loop_end)
-       p = loop_start;
+      if (p == loop->end)
+       p = loop->start;
     }
 
   return 0;
@@ -3618,7 +3657,7 @@ struct iv_class *loop_iv_list;
 /* Givs made from biv increments are always splittable for loop unrolling.
    Since there is no regscan info for them, we have to keep track of them
    separately.  */
-int first_increment_giv, last_increment_giv;
+unsigned int first_increment_giv, last_increment_giv;
 
 /* Communication with routines called via `note_stores'.  */
 
@@ -3661,25 +3700,12 @@ static rtx addr_placeholder;
    valid index in several tables including 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. 
-   
-   SCAN_START is the first instruction in the loop, as the loop would
-   actually be executed.  END is the NOTE_INSN_LOOP_END.  LOOP_TOP is
-   the first instruction in the loop, as it is layed out in the
-   instruction stream.  LOOP_START is the NOTE_INSN_LOOP_BEG.
-   LOOP_CONT is the NOTE_INSN_LOOP_CONT.  */
+   But scan_loop must check regnos to make sure they are in bounds.   */
 
 static void
-strength_reduce (scan_start, end, loop_top, insn_count,
-                loop_start, loop_end, loop_info, loop_cont, unroll_p, bct_p)
-     rtx scan_start;
-     rtx end;
-     rtx loop_top;
+strength_reduce (loop, insn_count, unroll_p, bct_p)
+     struct loop *loop;
      int insn_count;
-     rtx loop_start;
-     rtx loop_end;
-     struct loop_info *loop_info;
-     rtx loop_cont;
      int unroll_p, bct_p ATTRIBUTE_UNUSED;
 {
   rtx p;
@@ -3699,6 +3725,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
   int past_loop_latch = 0;
   /* Temporary list pointers for traversing loop_iv_list.  */
   struct iv_class *bl, **backbl;
+  struct loop_info *loop_info = LOOP_INFO (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
@@ -3706,26 +3733,29 @@ strength_reduce (scan_start, end, loop_top, insn_count,
   /* ??? 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;
+  rtx *reg_map = NULL;
   int reg_map_size;
   int call_seen;
   rtx test;
   rtx end_insert_before;
   int loop_depth = 0;
   int n_extra_increment;
-  int unrolled_insn_copies;
-
-  /* If scan_start points to the loop exit test, we have to be wary of
+  int unrolled_insn_copies = 0;
+  rtx loop_start = loop->start;
+  rtx loop_end = loop->end;
+  rtx loop_scan_start = loop->scan_start;
+  rtx loop_top = loop->top;
+  rtx loop_cont = loop->cont;
+
+  /* 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 (scan_start) != prev_nonnote_insn (loop_start))
-    maybe_multiple = back_branch_in_range_p (scan_start, loop_start, loop_end);
+  if (prev_nonnote_insn (loop_scan_start) != prev_nonnote_insn (loop_start))
+    maybe_multiple = back_branch_in_range_p (loop, loop_scan_start);
 
   VARRAY_INT_INIT (reg_iv_type, max_reg_before_loop, "reg_iv_type");
   VARRAY_GENERIC_PTR_INIT (reg_iv_info, max_reg_before_loop, "reg_iv_info");
   reg_biv_class = (struct iv_class **)
-    alloca (max_reg_before_loop * sizeof (struct iv_class *));
-  bzero ((char *) reg_biv_class, (max_reg_before_loop
-                                 * sizeof (struct iv_class *)));
+    xcalloc (max_reg_before_loop, sizeof (struct iv_class *));
 
   loop_iv_list = 0;
   addr_placeholder = gen_reg_rtx (Pmode);
@@ -3744,9 +3774,9 @@ strength_reduce (scan_start, end, loop_top, insn_count,
 
   /* Scan through loop to find all possible bivs.  */
 
-  for (p = next_insn_in_loop (scan_start, scan_start, end, loop_top);
+  for (p = next_insn_in_loop (loop, loop_scan_start);
        p != NULL_RTX;
-       p = next_insn_in_loop (p, scan_start, end, loop_top))
+       p = next_insn_in_loop (loop, p))
     {
       if (GET_CODE (p) == INSN
          && (set = single_set (p))
@@ -3757,9 +3787,12 @@ strength_reduce (scan_start, end, loop_top, insn_count,
              && REGNO (dest_reg) >= FIRST_PSEUDO_REGISTER
              && REG_IV_TYPE (REGNO (dest_reg)) != NOT_BASIC_INDUCT)
            {
-             if (basic_induction_var (SET_SRC (set), GET_MODE (SET_SRC (set)),
+             int multi_insn_incr = 0;
+
+             if (basic_induction_var (loop, SET_SRC (set),
+                                      GET_MODE (SET_SRC (set)),
                                       dest_reg, p, &inc_val, &mult_val,
-                                      &location))
+                                      &location, &multi_insn_incr))
                {
                  /* It is a possible basic induction variable.
                     Create and initialize an induction structure for it.  */
@@ -3768,7 +3801,8 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                    = (struct induction *) alloca (sizeof (struct induction));
 
                  record_biv (v, p, dest_reg, inc_val, mult_val, location,
-                             not_every_iteration, maybe_multiple);
+                             not_every_iteration, maybe_multiple, 
+                             multi_insn_incr);
                  REG_IV_TYPE (REGNO (dest_reg)) = BASIC_INDUCT;
                }
              else if (REGNO (dest_reg) < max_reg_before_loop)
@@ -3791,15 +3825,15 @@ strength_reduce (scan_start, end, loop_top, insn_count,
          while (1)
            {
              insn = NEXT_INSN (insn);
-             if (insn == scan_start)
+             if (insn == loop_scan_start)
                break;
-             if (insn == end)
+             if (insn == loop_end)
                {
                  if (loop_top != 0)
                    insn = loop_top;
                  else
                    break;
-                 if (insn == scan_start)
+                 if (insn == loop_scan_start)
                    break;
                }
 
@@ -3807,7 +3841,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                  && GET_CODE (PATTERN (insn)) != RETURN
                  && (! condjump_p (insn)
                      || (JUMP_LABEL (insn) != 0
-                         && JUMP_LABEL (insn) != scan_start
+                         && JUMP_LABEL (insn) != loop_scan_start
                          && ! loop_insn_first_p (p, JUMP_LABEL (insn)))))
                {
                  maybe_multiple = 1;
@@ -3833,11 +3867,9 @@ strength_reduce (scan_start, end, loop_top, insn_count,
 
          /* If this is a jump outside the loop, then it also doesn't
             matter.  Check to see if the target of this branch is on the
-            loop_number_exits_labels list.  */
+            loop->exits_labels list.  */
             
-         for (label = loop_number_exit_labels[uid_loop_num[INSN_UID (loop_start)]];
-              label;
-              label = LABEL_NEXTREF (label))
+         for (label = loop->exit_labels; label; label = LABEL_NEXTREF (label))
            if (XEXP (label, 0) == JUMP_LABEL (p))
              break;
 
@@ -3871,7 +3903,8 @@ strength_reduce (scan_start, end, loop_top, insn_count,
         Note that LOOP_TOP is only set for rotated loops and we need
         this check for all loops, so compare against the CODE_LABEL
         which immediately follows LOOP_START.  */
-      if (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == NEXT_INSN (loop_start))
+      if (GET_CODE (p) == JUMP_INSN 
+         && JUMP_LABEL (p) == NEXT_INSN (loop_start))
        past_loop_latch = 1;
 
       /* Unlike in the code motion pass where MAYBE_NEVER indicates that
@@ -3896,6 +3929,8 @@ strength_reduce (scan_start, end, loop_top, insn_count,
      Make a sanity check against n_times_set.  */
   for (backbl = &loop_iv_list, bl = *backbl; bl; bl = bl->next)
     {
+      int fail = 0;
+
       if (REG_IV_TYPE (bl->regno) != BASIC_INDUCT
          /* Above happens if register modified by subreg, etc.  */
          /* Make sure it is not recognized as a basic induction var: */
@@ -3903,6 +3938,21 @@ strength_reduce (scan_start, end, loop_top, insn_count,
          /* If never incremented, it is invariant that we decided not to
             move.  So leave it alone.  */
          || ! bl->incremented)
+       fail = 1;
+      else if (bl->biv_count > 1)
+       {
+         /* ??? If we have multiple increments for this BIV, and any of
+            them take multiple insns to perform the increment, drop the
+            BIV, since the bit below that converts the extra increments
+            into GIVs can't handle the multiple insn increment.  */
+         
+         struct induction *v;
+         for (v = bl->biv; v ; v = v->next_iv)
+           if (v->multi_insn_incr)
+             fail = 1;
+       }
+
+      if (fail)
        {
          if (loop_dump_stream)
            fprintf (loop_dump_stream, "Reg %d: biv discarded, %s\n",
@@ -3930,8 +3980,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
       /* Can still unroll the loop anyways, but indicate that there is no
         strength reduction info available.  */
       if (unroll_p)
-       unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
-                    loop_info, 0);
+       unroll_loop (loop, insn_count, end_insert_before, 0);
 
       goto egress;
     }
@@ -3949,7 +3998,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
 
       if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
          || GET_CODE (p) == CALL_INSN)
-       note_stores (PATTERN (p), record_initial);
+       note_stores (PATTERN (p), record_initial, NULL);
 
       /* Record any test of a biv that branches around the loop if no store
         between it and the start of loop.  We only care about tests with
@@ -3957,7 +4006,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
       if (GET_CODE (p) == JUMP_INSN
          && JUMP_LABEL (p) != 0
          && next_real_insn (JUMP_LABEL (p)) == next_real_insn (loop_end)
-         && (test = get_condition_for_loop (p)) != 0
+         && (test = get_condition_for_loop (loop, p)) != 0
          && GET_CODE (XEXP (test, 0)) == REG
          && REGNO (XEXP (test, 0)) < max_reg_before_loop
          && (bl = reg_biv_class[REGNO (XEXP (test, 0))]) != 0
@@ -4038,10 +4087,9 @@ strength_reduce (scan_start, end, loop_top, insn_count,
              && GET_CODE (src) == PLUS
              && GET_CODE (XEXP (src, 0)) == REG
              && CONSTANT_P (XEXP (src, 1))
-             && ((increment = biv_total_increment (bl, loop_start, loop_end))
-                 != NULL_RTX))
+             && ((increment = biv_total_increment (bl)) != NULL_RTX))
            {
-             int regno = REGNO (XEXP (src, 0));
+             unsigned int regno = REGNO (XEXP (src, 0));
 
              for (bl2 = loop_iv_list; bl2; bl2 = bl2->next)
                if (bl2->regno == regno)
@@ -4051,8 +4099,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
          /* Now, can we transform this biv into a giv?  */
          if (bl2
              && bl2->biv_count == 1
-             && rtx_equal_p (increment,
-                             biv_total_increment (bl2, loop_start, loop_end))
+             && 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,
@@ -4072,8 +4119,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                                  &SET_SRC (single_set (bl->biv->insn)),
                                  copy_rtx (src), 0))
            {
-             int loop_num = uid_loop_num[INSN_UID (loop_start)];
-             rtx dominator = loop_number_cont_dominator[loop_num];
+             rtx dominator = loop->cont_dominator;
              rtx giv = bl->biv->src_reg;
              rtx giv_insn = bl->biv->insn;
              rtx after_giv = NEXT_INSN (giv_insn);
@@ -4082,11 +4128,11 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                fprintf (loop_dump_stream, "is giv of biv %d\n", bl2->regno);
              /* Let this giv be discovered by the generic code.  */
              REG_IV_TYPE (bl->regno) = UNKNOWN_INDUCT;
-             reg_biv_class[bl->regno] = NULL_PTR;
+             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, scan_start)
+                 && ! 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)
@@ -4165,10 +4211,11 @@ strength_reduce (scan_start, end, loop_top, insn_count,
     n_extra_increment += bl->biv_count - 1;
 
   /* If the loop contains volatile memory references do not allow any
-     replacements to take place, since this could loose the volatile markers.  */
+     replacements to take place, since this could loose the volatile
+     markers.  */
   if (n_extra_increment  && ! loop_info->has_volatile)
     {
-      int nregs = first_increment_giv + n_extra_increment;
+      unsigned int nregs = first_increment_giv + n_extra_increment;
 
       /* Reallocate reg_iv_type and reg_iv_info.  */
       VARRAY_GROW (reg_iv_type, nregs);
@@ -4179,7 +4226,8 @@ strength_reduce (scan_start, end, loop_top, insn_count,
          struct induction **vp, *v, *next;
          int biv_dead_after_loop = 0;
 
-         /* The biv increments lists are in reverse order.  Fix this first.  */
+         /* 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;
@@ -4264,7 +4312,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
 
              for (last_use_insn = v->insn, p = NEXT_INSN (v->insn);
                   p != next->insn;
-                  p = next_insn_in_loop (p, scan_start, end, loop_top))
+                  p = next_insn_in_loop (loop, p))
                {
                  if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
                    continue;
@@ -4343,7 +4391,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                 remember the last insn that needed a replacement.  */
              for (last_use_insn = v->insn, p = NEXT_INSN (v->insn);
                   p != next->insn;
-                  p = next_insn_in_loop (p, scan_start, end, loop_top))
+                  p = next_insn_in_loop (loop, p))
                {
                  rtx note;
     
@@ -4364,7 +4412,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                }
     
              v->last_use = last_use_insn;
-             v->lifetime = INSN_LUID (v->insn) - INSN_LUID (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.  */
@@ -4373,7 +4421,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
 
              if (loop_dump_stream)
                fprintf (loop_dump_stream,
-                        "Increment %d of biv %d converted to giv %d.\n\n",
+                        "Increment %d of biv %d converted to giv %d.\n",
                         INSN_UID (v->insn), old_regno, new_regno);
            }
        }
@@ -4388,21 +4436,21 @@ strength_reduce (scan_start, end, loop_top, insn_count,
   not_every_iteration = 0;
   loop_depth = 0;
   maybe_multiple = 0;
-  p = scan_start;
+  p = loop_scan_start;
   while (1)
     {
       p = NEXT_INSN (p);
       /* At end of a straight-in loop, we are done.
         At end of a loop entered at the bottom, scan the top.  */
-      if (p == scan_start)
+      if (p == loop_scan_start)
        break;
-      if (p == end)
+      if (p == loop_end)
        {
          if (loop_top != 0)
            p = loop_top;
          else
            break;
-         if (p == scan_start)
+         if (p == loop_scan_start)
            break;
        }
 
@@ -4424,11 +4472,11 @@ strength_reduce (scan_start, end, loop_top, insn_count,
            continue;
 
          if (/* SET_SRC is a giv.  */
-             (general_induction_var (SET_SRC (set), &src_reg, &add_val,
+             (general_induction_var (loop, SET_SRC (set), &src_reg, &add_val,
                                      &mult_val, 0, &benefit)
               /* Equivalent expression is a giv.  */
               || ((regnote = find_reg_note (p, REG_EQUAL, NULL_RTX))
-                  && general_induction_var (XEXP (regnote, 0), &src_reg,
+                  && general_induction_var (loop, XEXP (regnote, 0), &src_reg,
                                             &add_val, &mult_val, 0,
                                             &benefit)))
              /* Don't try to handle any regs made by loop optimization.
@@ -4439,7 +4487,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
              /* This must be the only place where the register is set.  */
              && (VARRAY_INT (n_times_set, REGNO (dest_reg)) == 1
                  /* or all sets must be consecutive and make a giv.  */
-                 || (benefit = consec_sets_giv (benefit, p,
+                 || (benefit = consec_sets_giv (loop, benefit, p,
                                                 src_reg, dest_reg,
                                                 &add_val, &mult_val,
                                                 &last_consec_insn))))
@@ -4455,9 +4503,9 @@ strength_reduce (scan_start, end, loop_top, insn_count,
              if (VARRAY_INT (n_times_set, REGNO (dest_reg)) != 1)
                p = last_consec_insn;
 
-             record_giv (v, p, src_reg, dest_reg, mult_val, add_val, benefit,
-                         DEST_REG, not_every_iteration, maybe_multiple,
-                         NULL_PTR, loop_start, loop_end);
+             record_giv (loop, v, p, src_reg, dest_reg, mult_val, add_val,
+                         benefit, DEST_REG, not_every_iteration,
+                         maybe_multiple, NULL_PTR);
 
            }
        }
@@ -4467,15 +4515,15 @@ strength_reduce (scan_start, end, loop_top, insn_count,
       /* This resulted in worse code on a VAX 8600.  I wonder if it
         still does.  */
       if (GET_CODE (p) == INSN)
-       find_mem_givs (PATTERN (p), p, not_every_iteration, maybe_multiple,
-                      loop_start, loop_end);
+       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.  */
       if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
        || GET_CODE (p) == CODE_LABEL)
-       update_giv_derive (p);
+       update_giv_derive (loop, p);
 
       /* 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
@@ -4492,15 +4540,15 @@ strength_reduce (scan_start, end, loop_top, insn_count,
          while (1)
            {
              insn = NEXT_INSN (insn);
-             if (insn == scan_start)
+             if (insn == loop_scan_start)
                break;
-             if (insn == end)
+             if (insn == loop_end)
                {
                  if (loop_top != 0)
                    insn = loop_top;
                  else
                    break;
-                 if (insn == scan_start)
+                 if (insn == loop_scan_start)
                    break;
                }
 
@@ -4508,7 +4556,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                  && GET_CODE (PATTERN (insn)) != RETURN
                  && (! condjump_p (insn)
                      || (JUMP_LABEL (insn) != 0
-                         && JUMP_LABEL (insn) != scan_start
+                         && JUMP_LABEL (insn) != loop_scan_start
                          && (INSN_UID (JUMP_LABEL (insn)) >= max_uid_for_loop
                              || INSN_UID (insn) >= max_uid_for_loop
                              || (INSN_LUID (JUMP_LABEL (insn))
@@ -4537,11 +4585,9 @@ strength_reduce (scan_start, end, loop_top, insn_count,
 
          /* If this is a jump outside the loop, then it also doesn't
             matter.  Check to see if the target of this branch is on the
-            loop_number_exits_labels list.  */
+            loop->exits_labels list.  */
             
-         for (label = loop_number_exit_labels[uid_loop_num[INSN_UID (loop_start)]];
-              label;
-              label = LABEL_NEXTREF (label))
+         for (label = loop->exit_labels; label; label = LABEL_NEXTREF (label))
            if (XEXP (label, 0) == JUMP_LABEL (p))
              break;
 
@@ -4587,7 +4633,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
      be called after all giv's have been identified, since otherwise it may
      fail if the iteration variable is a giv.  */
 
-  loop_iterations (loop_start, loop_end, loop_info);
+  loop_iterations (loop);
 
   /* 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
@@ -4600,20 +4646,19 @@ strength_reduce (scan_start, end, loop_top, insn_count,
 
       for (v = bl->giv; v; v = v->next_iv)
        if (! v->replaceable && ! v->not_replaceable)
-         check_final_value (v, loop_start, loop_end, loop_info->n_iterations);
+         check_final_value (loop, v);
     }
 
   /* Try to prove that the loop counter variable (if any) is always
      nonnegative; if so, record that fact with a REG_NONNEG note
      so that "decrement and branch until zero" insn can be used.  */
-  check_dbra_loop (loop_end, insn_count, loop_start, loop_info);
+  check_dbra_loop (loop, insn_count);
 
   /* Create reg_map to hold substitutions for replaceable giv regs.
      Some givs might have been made from biv increments, so look at
      reg_iv_type for a suitable size.  */
   reg_map_size = reg_iv_type->num_elements;
-  reg_map = (rtx *) alloca (reg_map_size * sizeof (rtx));
-  bzero ((char *) reg_map, reg_map_size * sizeof (rtx));
+  reg_map = (rtx *) xcalloc (reg_map_size, sizeof (rtx));
 
   /* Examine each iv class for feasibility of strength reduction/induction
      variable elimination.  */
@@ -4650,14 +4695,13 @@ strength_reduce (scan_start, end, loop_top, insn_count,
           && ! bl->nonneg
 #endif
           && ! reg_mentioned_p (bl->biv->dest_reg, SET_SRC (bl->init_set)))
-         || ((final_value = final_biv_value (bl, loop_start, loop_end, 
-                                             loop_info->n_iterations))
+         || ((final_value = final_biv_value (loop, bl))
 #ifdef HAVE_decrement_and_branch_until_zero
              && ! bl->nonneg
 #endif
              ))
-       bl->eliminable = maybe_eliminate_biv (bl, loop_start, end, 0,
-                                             threshold, insn_count);
+       bl->eliminable = maybe_eliminate_biv (loop, bl, 0, threshold, 
+                                             insn_count);
       else
        {
          if (loop_dump_stream)
@@ -4821,7 +4865,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
          VARRAY_GROW (reg_iv_type, nregs);
          VARRAY_GROW (reg_iv_info, nregs);
        }
-      recombine_givs (bl, loop_start, loop_end, unroll_p);
+      recombine_givs (loop, bl, unroll_p);
 
       /* Reduce each giv that we decided to reduce.  */
 
@@ -4923,11 +4967,11 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                  /* 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 (scan_start)
+                           && (INSN_LUID (v->insn) < INSN_LUID (loop_scan_start)
                                || (INSN_LUID (bl->biv->insn)
-                                   > INSN_LUID (scan_start))))
-                          || (INSN_LUID (v->insn) < INSN_LUID (scan_start)
-                              && (INSN_LUID (scan_start)
+                                   > 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
@@ -5054,7 +5098,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                 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_number_exit_count[uid_loop_num[INSN_UID (loop_start)]])
+             if (loop->exit_count)
                insert_before = loop_start;
              else
                insert_before = end_insert_before;
@@ -5122,9 +5166,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
         doing so in the rare cases where it can occur.  */
 
       if (all_reduced == 1 && bl->eliminable
-         && maybe_eliminate_biv (bl, loop_start, end, 1,
-                                 threshold, insn_count))
-
+         && maybe_eliminate_biv (loop, bl, 1, threshold, insn_count))
        {
          /* ?? If we created a new test to bypass the loop entirely,
             or otherwise drop straight in, based on this test, then
@@ -5146,7 +5188,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                 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_number_exit_count[uid_loop_num[INSN_UID (loop_start)]])
+             if (loop->exit_count)
                insert_before = loop_start;
              else
                insert_before = end_insert_before;
@@ -5177,7 +5219,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
   /* Go through all the instructions in the loop, making all the
      register substitutions scheduled in REG_MAP.  */
 
-  for (p = loop_start; p != 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)
       {
@@ -5220,14 +5262,13 @@ strength_reduce (scan_start, end, loop_top, insn_count,
   if (unroll_p
       || (loop_info->n_iterations > 0
          && unrolled_insn_copies <= insn_count))
-    unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
-                loop_info, 1);
+    unroll_loop (loop, insn_count, end_insert_before, 1);
 
 #ifdef HAVE_decrement_and_branch_on_count
   /* Instrument the loop with BCT insn.  */
   if (HAVE_decrement_and_branch_on_count && bct_p
       && flag_branch_on_count_reg)
-    insert_bct (loop_start, loop_end, loop_info);
+    insert_bct (loop);
 #endif  /* HAVE_decrement_and_branch_on_count */
 
   if (loop_dump_stream)
@@ -5236,6 +5277,9 @@ strength_reduce (scan_start, end, loop_top, insn_count,
 egress:
   VARRAY_FREE (reg_iv_type);
   VARRAY_FREE (reg_iv_info);
+  free (reg_biv_class);
+  if (reg_map)
+    free (reg_map);
 }
 \f
 /* Return 1 if X is a valid source for an initial value (or as value being
@@ -5284,12 +5328,11 @@ valid_initial_value_p (x, insn, call_seen, loop_start)
    more thanonce in each loop iteration.  */
 
 static void
-find_mem_givs (x, insn, not_every_iteration, maybe_multiple, loop_start,
-              loop_end)
+find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
+     const struct loop *loop;
      rtx x;
      rtx insn;
      int not_every_iteration, maybe_multiple;
-     rtx loop_start, loop_end;
 {
   register int i, j;
   register enum rtx_code code;
@@ -5327,16 +5370,16 @@ find_mem_givs (x, insn, not_every_iteration, maybe_multiple, loop_start,
           it comes time to combine a set of related DEST_ADDR GIVs, since
           this one would not be seen.   */
 
-       if (general_induction_var (XEXP (x, 0), &src_reg, &add_val,
+       if (general_induction_var (loop, XEXP (x, 0), &src_reg, &add_val,
                                   &mult_val, 1, &benefit))
          {
            /* Found one; record it.  */
            struct induction *v
              = (struct induction *) oballoc (sizeof (struct induction));
 
-           record_giv (v, insn, src_reg, addr_placeholder, mult_val,
+           record_giv (loop, v, insn, src_reg, addr_placeholder, mult_val,
                        add_val, benefit, DEST_ADDR, not_every_iteration,
-                       maybe_multiple, &XEXP (x, 0), loop_start, loop_end);
+                       maybe_multiple, &XEXP (x, 0));
 
            v->mem_mode = GET_MODE (x);
          }
@@ -5352,12 +5395,12 @@ find_mem_givs (x, insn, not_every_iteration, maybe_multiple, loop_start,
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     if (fmt[i] == 'e')
-      find_mem_givs (XEXP (x, i), insn, not_every_iteration, maybe_multiple,
-                    loop_start, loop_end);
+      find_mem_givs (loop, XEXP (x, i), insn, not_every_iteration,
+                    maybe_multiple);
     else if (fmt[i] == 'E')
       for (j = 0; j < XVECLEN (x, i); j++)
-       find_mem_givs (XVECEXP (x, i, j), insn, not_every_iteration,
-                      maybe_multiple, loop_start, loop_end);
+       find_mem_givs (loop, XVECEXP (x, i, j), insn, not_every_iteration,
+                      maybe_multiple);
 }
 \f
 /* Fill in the data about one biv update.
@@ -5378,7 +5421,7 @@ find_mem_givs (x, insn, not_every_iteration, maybe_multiple, loop_start,
 
 static void
 record_biv (v, insn, dest_reg, inc_val, mult_val, location,
-           not_every_iteration, maybe_multiple)
+           not_every_iteration, maybe_multiple, multi_insn_incr)
      struct induction *v;
      rtx insn;
      rtx dest_reg;
@@ -5387,6 +5430,7 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
      rtx *location;
      int not_every_iteration;
      int maybe_multiple;
+     int multi_insn_incr;
 {
   struct iv_class *bl;
 
@@ -5400,6 +5444,7 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
   v->always_computable = ! not_every_iteration;
   v->always_executed = ! not_every_iteration;
   v->maybe_multiple = maybe_multiple;
+  v->multi_insn_incr = multi_insn_incr;
 
   /* Add this to the reg's iv_class, creating a class
      if this is the first incrementation of the reg.  */
@@ -5478,9 +5523,9 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
    LOCATION points to the place where this giv's value appears in INSN.  */
 
 static void
-record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
-           type, not_every_iteration, maybe_multiple, location, loop_start,
-           loop_end)
+record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
+           type, not_every_iteration, maybe_multiple, location)
+     const struct loop *loop;
      struct induction *v;
      rtx insn;
      rtx src_reg;
@@ -5490,7 +5535,6 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
      enum g_types type;
      int not_every_iteration, maybe_multiple;
      rtx *location;
-     rtx loop_start, loop_end;
 {
   struct induction *b;
   struct iv_class *bl;
@@ -5507,6 +5551,7 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
   v->cant_derive = 0;
   v->combined_with = 0;
   v->maybe_multiple = maybe_multiple;
+  v->multi_insn_incr = 0;
   v->maybe_dead = 0;
   v->derive_adjustment = 0;
   v->same = 0;
@@ -5590,7 +5635,8 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
 
       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))] < INSN_LUID (loop_end)
+         && uid_luid[REGNO_LAST_UID (REGNO (dest_reg))] 
+         < INSN_LUID (loop->end)
          && (! not_every_iteration
              || last_use_this_basic_block (dest_reg, insn)))
        {
@@ -5627,7 +5673,7 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
             biv update to before it, then this giv is not replaceable.  */
          if (v->replaceable)
            for (b = bl->biv; b; b = b->next_iv)
-             if (back_branch_in_range_p (b->insn, loop_start, loop_end))
+             if (back_branch_in_range_p (loop, b->insn))
                {
                  v->replaceable = 0;
                  v->not_replaceable = 1;
@@ -5725,10 +5771,9 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
    have been identified.  */
 
 static void
-check_final_value (v, loop_start, loop_end, n_iterations)
+check_final_value (loop, v)
+     const struct loop *loop;
      struct induction *v;
-     rtx loop_start, loop_end;
-     unsigned HOST_WIDE_INT n_iterations;
 {
   struct iv_class *bl;
   rtx final_value = 0;
@@ -5755,7 +5800,7 @@ check_final_value (v, loop_start, loop_end, n_iterations)
   v->replaceable = 0;
 #endif
 
-  if ((final_value = final_giv_value (v, loop_start, loop_end, n_iterations))
+  if ((final_value = final_giv_value (loop, v))
       && (v->always_computable || last_use_this_basic_block (v->dest_reg, v->insn)))
     {
       int biv_increment_seen = 0;
@@ -5787,8 +5832,8 @@ check_final_value (v, loop_start, loop_end, n_iterations)
       while (1)
        {
          p = NEXT_INSN (p);
-         if (p == loop_end)
-           p = NEXT_INSN (loop_start);
+         if (p == loop->end)
+           p = NEXT_INSN (loop->start);
          if (p == v->insn)
            break;
 
@@ -5821,17 +5866,17 @@ check_final_value (v, loop_start, loop_end, n_iterations)
          while (1)
            {
              p = NEXT_INSN (p);
-             if (p == loop_end)
-               p = NEXT_INSN (loop_start);
+             if (p == loop->end)
+               p = NEXT_INSN (loop->start);
              if (p == last_giv_use)
                break;
 
              if (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p)
                  && LABEL_NAME (JUMP_LABEL (p))
                  && ((loop_insn_first_p (JUMP_LABEL (p), v->insn)
-                      && loop_insn_first_p (loop_start, JUMP_LABEL (p)))
+                      && loop_insn_first_p (loop->start, JUMP_LABEL (p)))
                      || (loop_insn_first_p (last_giv_use, JUMP_LABEL (p))
-                         && loop_insn_first_p (JUMP_LABEL (p), loop_end))))
+                         && loop_insn_first_p (JUMP_LABEL (p), loop->end))))
                {
                  v->replaceable = 0;
                  v->not_replaceable = 1;
@@ -5867,7 +5912,8 @@ check_final_value (v, loop_start, loop_end, n_iterations)
    The cases we look at are when a label or an update to a biv is passed.  */
 
 static void
-update_giv_derive (p)
+update_giv_derive (loop, p)
+     const  struct loop *loop;
      rtx p;
 {
   struct iv_class *bl;
@@ -5935,14 +5981,16 @@ update_giv_derive (p)
                  tem = 0;
 
                  if (biv->mult_val == const1_rtx)
-                   tem = simplify_giv_expr (gen_rtx_MULT (giv->mode,
+                   tem = simplify_giv_expr (loop,
+                                            gen_rtx_MULT (giv->mode,
                                                           biv->add_val,
                                                           giv->mult_val),
                                             &dummy);
 
                  if (tem && giv->derive_adjustment)
                    tem = simplify_giv_expr
-                     (gen_rtx_PLUS (giv->mode, tem, giv->derive_adjustment),
+                     (loop,
+                      gen_rtx_PLUS (giv->mode, tem, giv->derive_adjustment),
                       &dummy);
 
                  if (tem)
@@ -5995,14 +6043,17 @@ update_giv_derive (p)
    If we cannot find a biv, we return 0.  */
 
 static int
-basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val, location)
+basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val,
+                    location, multi_insn_incr)
+     const struct loop *loop;
      register rtx x;
      enum machine_mode mode;
-     rtx p;
      rtx dest_reg;
+     rtx p;
      rtx *inc_val;
      rtx *mult_val;
      rtx **location;
+     int *multi_insn_incr;
 {
   register enum rtx_code code;
   rtx *argp, arg;
@@ -6031,7 +6082,7 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val, location)
        return 0;
 
       arg = *argp;
-      if (invariant_p (arg) != 1)
+      if (loop_invariant_p (loop, arg) != 1)
        return 0;
 
       *inc_val = convert_modes (GET_MODE (dest_reg), GET_MODE (x), arg, 0);
@@ -6043,8 +6094,10 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val, location)
       /* If this is a SUBREG for a promoted variable, check the inner
         value.  */
       if (SUBREG_PROMOTED_VAR_P (x))
-       return basic_induction_var (SUBREG_REG (x), GET_MODE (SUBREG_REG (x)),
-                                   dest_reg, p, inc_val, mult_val, location);
+       return basic_induction_var (loop, SUBREG_REG (x),
+                                   GET_MODE (SUBREG_REG (x)),
+                                   dest_reg, p, inc_val, mult_val, location,
+                                   multi_insn_incr);
       return 0;
 
     case REG:
@@ -6069,14 +6122,20 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val, location)
               || (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 (SET_SRC (set),
+             && 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;
+                                     inc_val, mult_val, location,
+                                     multi_insn_incr))
+           {
+             *multi_insn_incr = 1;
+             return 1;
+           }
        }
       /* ... fall through ...  */
 
@@ -6085,7 +6144,7 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val, location)
         as a biv of the outer loop,
         causing code to be moved INTO the inner loop.  */
     case MEM:
-      if (invariant_p (x) != 1)
+      if (loop_invariant_p (loop, x) != 1)
        return 0;
     case CONST_INT:
     case SYMBOL_REF:
@@ -6093,7 +6152,7 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val, location)
       /* 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.  */
-      if (this_loop_info.loops_enclosed == 1
+      if (loop->level == 1
          && GET_MODE_CLASS (mode) != MODE_CC
          && GET_MODE_CLASS (GET_MODE (dest_reg)) != MODE_CC)
        {
@@ -6106,8 +6165,9 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val, location)
        return 0;
 
     case SIGN_EXTEND:
-      return basic_induction_var (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
-                                 dest_reg, p, inc_val, mult_val, location);
+      return basic_induction_var (loop, XEXP (x, 0), GET_MODE (XEXP (x, 0)),
+                                 dest_reg, p, inc_val, mult_val, location,
+                                 multi_insn_incr);
 
     case ASHIFTRT:
       /* Similar, since this can be a sign extension.  */
@@ -6124,11 +6184,15 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val, location)
          && GET_CODE (XEXP (x, 1)) == CONST_INT
          && INTVAL (XEXP (x, 1)) >= 0
          && GET_CODE (SET_SRC (set)) == ASHIFT
-         && XEXP (x, 1) == XEXP (SET_SRC (set), 1))
-       return basic_induction_var (XEXP (SET_SRC (set), 0),
-                                   GET_MODE (XEXP (x, 0)),
-                                   dest_reg, insn, inc_val, mult_val,
-                                   location);
+         && XEXP (x, 1) == XEXP (SET_SRC (set), 1)
+         && basic_induction_var (loop, XEXP (SET_SRC (set), 0),
+                                 GET_MODE (XEXP (x, 0)),
+                                 dest_reg, insn, inc_val, mult_val,
+                                 location, multi_insn_incr))
+       {
+         *multi_insn_incr = 1;
+         return 1;
+       }
       return 0;
 
     default:
@@ -6151,7 +6215,8 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val, location)
      such that the value of X is biv * mult + add;  */
 
 static int
-general_induction_var (x, src_reg, add_val, mult_val, is_addr, pbenefit)
+general_induction_var (loop, x, src_reg, add_val, mult_val, is_addr, pbenefit)
+     const struct loop *loop;
      rtx x;
      rtx *src_reg;
      rtx *add_val;
@@ -6163,14 +6228,14 @@ general_induction_var (x, src_reg, add_val, mult_val, is_addr, pbenefit)
   char *storage;
 
   /* If this is an invariant, forget it, it isn't a giv.  */
-  if (invariant_p (x) == 1)
+  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;
-  x = simplify_giv_expr (x, pbenefit);
+  x = simplify_giv_expr (loop, x, pbenefit);
   if (x == 0)
     {
       obfree (storage);
@@ -6267,11 +6332,14 @@ general_induction_var (x, src_reg, add_val, mult_val, is_addr, pbenefit)
 
    *BENEFIT will be incremented by the benefit of any sub-giv encountered.  */
 
-static rtx sge_plus PROTO ((enum machine_mode, rtx, rtx));
-static rtx sge_plus_constant PROTO ((rtx, rtx));
+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 (x, benefit)
+simplify_giv_expr (loop, x, benefit)
+     const struct loop *loop;
      rtx x;
      int *benefit;
 {
@@ -6289,8 +6357,8 @@ simplify_giv_expr (x, benefit)
   switch (GET_CODE (x))
     {
     case PLUS:
-      arg0 = simplify_giv_expr (XEXP (x, 0), benefit);
-      arg1 = simplify_giv_expr (XEXP (x, 1), benefit);
+      arg0 = simplify_giv_expr (loop, XEXP (x, 0), benefit);
+      arg1 = simplify_giv_expr (loop, XEXP (x, 1), benefit);
       if (arg0 == 0 || arg1 == 0)
        return NULL_RTX;
 
@@ -6336,7 +6404,8 @@ simplify_giv_expr (x, benefit)
          case PLUS:
            /* (a + invar_1) + invar_2.  Associate.  */
            return
-             simplify_giv_expr (gen_rtx_PLUS (mode,
+             simplify_giv_expr (loop,
+                                gen_rtx_PLUS (mode,
                                               XEXP (arg0, 0),
                                               gen_rtx_PLUS (mode,
                                                             XEXP (arg0, 1),
@@ -6362,7 +6431,8 @@ simplify_giv_expr (x, benefit)
 
       if (GET_CODE (arg1) == PLUS)
          return
-           simplify_giv_expr (gen_rtx_PLUS (mode,
+           simplify_giv_expr (loop,
+                              gen_rtx_PLUS (mode,
                                             gen_rtx_PLUS (mode, arg0,
                                                           XEXP (arg1, 0)),
                                             XEXP (arg1, 1)),
@@ -6375,7 +6445,8 @@ simplify_giv_expr (x, benefit)
       if (!rtx_equal_p (arg0, arg1))
        return NULL_RTX;
 
-      return simplify_giv_expr (gen_rtx_MULT (mode,
+      return simplify_giv_expr (loop,
+                               gen_rtx_MULT (mode,
                                              XEXP (arg0, 0),
                                              gen_rtx_PLUS (mode,
                                                            XEXP (arg0, 1),
@@ -6384,7 +6455,8 @@ simplify_giv_expr (x, benefit)
 
     case MINUS:
       /* Handle "a - b" as "a + b * (-1)".  */
-      return simplify_giv_expr (gen_rtx_PLUS (mode,
+      return simplify_giv_expr (loop,
+                               gen_rtx_PLUS (mode,
                                              XEXP (x, 0),
                                              gen_rtx_MULT (mode,
                                                            XEXP (x, 1),
@@ -6392,8 +6464,8 @@ simplify_giv_expr (x, benefit)
                                benefit);
 
     case MULT:
-      arg0 = simplify_giv_expr (XEXP (x, 0), benefit);
-      arg1 = simplify_giv_expr (XEXP (x, 1), benefit);
+      arg0 = simplify_giv_expr (loop, XEXP (x, 0), benefit);
+      arg1 = simplify_giv_expr (loop, XEXP (x, 1), benefit);
       if (arg0 == 0 || arg1 == 0)
        return NULL_RTX;
 
@@ -6446,7 +6518,8 @@ simplify_giv_expr (x, benefit)
 
        case MULT:
          /* (a * invar_1) * invar_2.  Associate.  */
-         return simplify_giv_expr (gen_rtx_MULT (mode,
+         return simplify_giv_expr (loop,
+                                   gen_rtx_MULT (mode,
                                                  XEXP (arg0, 0),
                                                  gen_rtx_MULT (mode,
                                                                XEXP (arg0, 1),
@@ -6455,7 +6528,8 @@ simplify_giv_expr (x, benefit)
 
        case PLUS:
          /* (a + invar_1) * invar_2.  Distribute.  */
-         return simplify_giv_expr (gen_rtx_PLUS (mode,
+         return simplify_giv_expr (loop,
+                                   gen_rtx_PLUS (mode,
                                                  gen_rtx_MULT (mode,
                                                                XEXP (arg0, 0),
                                                                arg1),
@@ -6474,7 +6548,8 @@ simplify_giv_expr (x, benefit)
        return 0;
 
       return
-       simplify_giv_expr (gen_rtx_MULT (mode,
+       simplify_giv_expr (loop,
+                          gen_rtx_MULT (mode,
                                         XEXP (x, 0),
                                         GEN_INT ((HOST_WIDE_INT) 1
                                                  << INTVAL (XEXP (x, 1)))),
@@ -6482,12 +6557,14 @@ simplify_giv_expr (x, benefit)
 
     case NEG:
       /* "-a" is "a * (-1)" */
-      return simplify_giv_expr (gen_rtx_MULT (mode, XEXP (x, 0), constm1_rtx),
+      return simplify_giv_expr (loop,
+                               gen_rtx_MULT (mode, XEXP (x, 0), constm1_rtx),
                                benefit);
 
     case NOT:
       /* "~a" is "-a - 1". Silly, but easy.  */
-      return simplify_giv_expr (gen_rtx_MINUS (mode,
+      return simplify_giv_expr (loop,
+                               gen_rtx_MINUS (mode,
                                               gen_rtx_NEG (mode, XEXP (x, 0)),
                                               const1_rtx),
                                benefit);
@@ -6522,14 +6599,14 @@ simplify_giv_expr (x, benefit)
 
            if (v->derive_adjustment)
              tem = gen_rtx_MINUS (mode, tem, v->derive_adjustment);
-           return simplify_giv_expr (tem, benefit);
+           return simplify_giv_expr (loop, tem, benefit);
          }
 
        default:
          /* If it isn't an induction variable, and it is invariant, we
             may be able to simplify things further by looking through
             the bits we just moved outside the loop.  */
-         if (invariant_p (x) == 1)
+         if (loop_invariant_p (loop, x) == 1)
            {
              struct movable *m;
 
@@ -6541,7 +6618,8 @@ simplify_giv_expr (x, benefit)
                    /* If we match another movable, we must use that, as 
                       this one is going away.  */
                    if (m->match)
-                     return simplify_giv_expr (m->match->set_dest, benefit);
+                     return simplify_giv_expr (loop, m->match->set_dest, 
+                                               benefit);
 
                    /* If consec is non-zero, this is a member of a group of
                       instructions that were moved together.  We handle this
@@ -6575,7 +6653,7 @@ simplify_giv_expr (x, benefit)
                            || GET_CODE (tem) == CONST_INT
                            || GET_CODE (tem) == SYMBOL_REF)
                          {
-                           tem = simplify_giv_expr (tem, benefit);
+                           tem = simplify_giv_expr (loop, tem, benefit);
                            if (tem)
                              return tem;
                          }
@@ -6584,7 +6662,8 @@ simplify_giv_expr (x, benefit)
                            && GET_CODE (XEXP (XEXP (tem, 0), 0)) == SYMBOL_REF
                            && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)
                          {
-                           tem = simplify_giv_expr (XEXP (tem, 0), benefit);
+                           tem = simplify_giv_expr (loop, XEXP (tem, 0),
+                                                    benefit);
                            if (tem)
                              return tem;
                          }
@@ -6602,7 +6681,7 @@ simplify_giv_expr (x, benefit)
       if (GET_CODE (x) == USE)
        x = XEXP (x, 0);
 
-      if (invariant_p (x) == 1)
+      if (loop_invariant_p (loop, x) == 1)
        {
          if (GET_CODE (x) == CONST_INT)
            return x;
@@ -6688,8 +6767,9 @@ sge_plus (mode, x, y)
    *MULT_VAL and *ADD_VAL.  */
 
 static int
-consec_sets_giv (first_benefit, p, src_reg, dest_reg,
+consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
                 add_val, mult_val, last_consec_insn)
+     const struct loop *loop;
      int first_benefit;
      rtx p;
      rtx src_reg;
@@ -6738,11 +6818,11 @@ consec_sets_giv (first_benefit, p, src_reg, dest_reg,
          && (set = single_set (p))
          && GET_CODE (SET_DEST (set)) == REG
          && SET_DEST (set) == dest_reg
-         && (general_induction_var (SET_SRC (set), &src_reg,
+         && (general_induction_var (loop, SET_SRC (set), &src_reg,
                                     add_val, mult_val, 0, &benefit)
              /* Giv created by equivalent expression.  */
              || ((temp = find_reg_note (p, REG_EQUAL, NULL_RTX))
-                 && general_induction_var (XEXP (temp, 0), &src_reg,
+                 && general_induction_var (loop, XEXP (temp, 0), &src_reg,
                                            add_val, mult_val, 0, &benefit)))
          && src_reg == v->src_reg)
        {
@@ -7014,9 +7094,14 @@ struct combine_givs_stats
 };
 
 static int
-cmp_combine_givs_stats (x, y)
-     struct combine_givs_stats *x, *y;
+cmp_combine_givs_stats (xp, yp)
+     const PTR xp;
+     const PTR yp;
 {
+  const struct combine_givs_stats * const x =
+    (const struct combine_givs_stats *) xp;
+  const struct combine_givs_stats * const y =
+    (const struct combine_givs_stats *) yp;
   int d;
   d = y->total_benefit - x->total_benefit;
   /* Stabilize the sort.  */
@@ -7055,11 +7140,8 @@ combine_givs (bl)
     if (!g1->ignore)
       giv_array[i++] = g1;
 
-  stats = (struct combine_givs_stats *) alloca (giv_count * sizeof (*stats));
-  bzero ((char *) stats, giv_count * sizeof (*stats));
-
-  can_combine = (rtx *) alloca (giv_count * giv_count * sizeof(rtx));
-  bzero ((char *) can_combine, giv_count * giv_count * sizeof(rtx));
+  stats = (struct combine_givs_stats *) xcalloc (giv_count, sizeof (*stats));
+  can_combine = (rtx *) xcalloc (giv_count, giv_count * sizeof(rtx));
 
   for (i = 0; i < giv_count; i++)
     {
@@ -7189,6 +7271,10 @@ restart:
          goto restart;
        }
     }
+
+  /* Clean up.  */
+  free (stats);
+  free (can_combine);
 }
 \f
 struct recombine_givs_stats
@@ -7201,9 +7287,14 @@ struct recombine_givs_stats
    when scanning the array starting at the end, thus the arguments are
    used in reverse.  */
 static int
-cmp_recombine_givs_stats (x, y)
-     struct recombine_givs_stats *x, *y;
+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.  */
@@ -7304,9 +7395,9 @@ find_life_end (x, stats, insn, biv)
    This tends to shorten giv lifetimes, and helps the next step:
    try to derive givs from other givs.  */
 static void
-recombine_givs (bl, loop_start, loop_end, unroll_p)
+recombine_givs (loop, bl, unroll_p)
+     const struct loop *loop;
      struct iv_class *bl;
-     rtx loop_start, loop_end;
      int unroll_p;
 {
   struct induction *v, **giv_array, *last_giv;
@@ -7321,8 +7412,8 @@ recombine_givs (bl, loop_start, loop_end, unroll_p)
        giv_count++;
     }
   giv_array
-    = (struct induction **) alloca (giv_count * sizeof (struct induction *));
-  stats = (struct recombine_givs_stats *) alloca (giv_count * sizeof *stats);
+    = (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.  */
@@ -7459,7 +7550,7 @@ recombine_givs (bl, loop_start, loop_end, unroll_p)
              else
                {
                  stats[i].end_luid = uid_luid[REGNO_LAST_UID (regno)];
-                 if (stats[i].end_luid > INSN_LUID (loop_end))
+                 if (stats[i].end_luid > INSN_LUID (loop->end))
                    {
                      stats[i].end_luid = -1;
                      ends_need_computing++;
@@ -7474,12 +7565,12 @@ recombine_givs (bl, loop_start, loop_end, unroll_p)
   if (ends_need_computing)
     {
       rtx biv = bl->biv->src_reg;
-      rtx p = loop_end;
+      rtx p = loop->end;
 
       do
        {
-         if (p == loop_start)
-           p = loop_end;
+         if (p == loop->start)
+           p = loop->end;
          p = PREV_INSN (p);
          if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
            continue;
@@ -7534,7 +7625,7 @@ recombine_givs (bl, loop_start, loop_end, unroll_p)
      LAST_GIV.  */
   for (i = giv_count - 1; i >= 0; i = rescan)
     {
-      int life_start, life_end;
+      int life_start = 0, life_end = 0;
 
       for (last_giv = 0, rescan = -1; i >= 0; i--)
        {
@@ -7565,8 +7656,8 @@ recombine_givs (bl, loop_start, loop_end, unroll_p)
                  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))
+             && ((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)
@@ -7613,6 +7704,10 @@ recombine_givs (bl, loop_start, loop_end, unroll_p)
            rescan = i;
        }
     }
+
+  /* Clean up.  */
+  free (giv_array);
+  free (stats);
 }
 \f
 /* EMIT code before INSERT_BEFORE to set REG = B * M + A.  */
@@ -7756,11 +7851,9 @@ product_cheap_p (a, b)
    final_[bg]iv_value.  */
 
 static int
-check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
-     rtx loop_end;
+check_dbra_loop (loop, insn_count)
+     struct loop *loop;
      int insn_count;
-     rtx loop_start;
-     struct loop_info *loop_info;
 {
   struct iv_class *bl;
   rtx reg;
@@ -7774,12 +7867,15 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
   rtx jump;
   rtx first_compare;
   int compare_and_branch;
+  rtx loop_start = loop->start;
+  rtx loop_end = loop->end;
+  struct loop_info *loop_info = LOOP_INFO (loop);
 
   /* If last insn is a conditional branch, and the insn before tests a
      register value, try to optimize it.  Otherwise, we can't do anything.  */
 
   jump = PREV_INSN (loop_end);
-  comparison = get_condition_for_loop (jump);
+  comparison = get_condition_for_loop (loop, jump);
   if (comparison == 0)
     return 0;
 
@@ -7801,6 +7897,7 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
   for (bl = loop_iv_list; bl; bl = bl->next)
     {
       if (bl->biv_count == 1
+         && ! bl->biv->maybe_multiple
          && bl->biv->dest_reg == XEXP (comparison, 0)
          && ! reg_used_between_p (regno_reg_rtx[bl->regno], bl->biv->insn,
                                   first_compare))
@@ -7849,7 +7946,7 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
          if (GET_CODE (p) != JUMP_INSN)
            continue;
 
-         before_comparison = get_condition_for_loop (p);
+         before_comparison = get_condition_for_loop (loop, p);
          if (before_comparison
              && XEXP (before_comparison, 0) == bl->biv->dest_reg
              && GET_CODE (before_comparison) == LT
@@ -7887,8 +7984,7 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
         which is reversible.  */
       int reversible_mem_store = 1;
 
-      if (bl->giv_count == 0
-         && ! loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]])
+      if (bl->giv_count == 0 && ! loop->exit_count)
        {
          rtx bivreg = regno_reg_rtx[bl->regno];
 
@@ -7905,10 +8001,23 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
                    && 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))
-                 /* Don't bother about the end test.  */
-                 ;
+               else if ((p == prev_nonnote_insn (prev_nonnote_insn (loop_end))
+                         || p == prev_nonnote_insn (loop_end))
+                        && reg_mentioned_p (bivreg, PATTERN (p)))
+                 {
+                   /* If either of these insns uses the biv and sets a pseudo
+                      that has more than one usage, then the biv has uses
+                      other than counting since it's used to derive a value
+                      that is used more than one time.  */
+                   int note_set_pseudo_multiple_uses_retval = 0;
+                   note_stores (PATTERN (p), note_set_pseudo_multiple_uses,
+                                &note_set_pseudo_multiple_uses_retval);
+                   if (note_set_pseudo_multiple_uses_retval)
+                     {
+                       no_use_except_counting = 0;
+                       break;
+                     }
+                 }
                else if (reg_mentioned_p (bivreg, PATTERN (p)))
                  {
                    no_use_except_counting = 0;
@@ -7923,7 +8032,7 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
        {
          for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
            if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
-             num_nonfixed_reads += count_nonfixed_reads (PATTERN (p));
+             num_nonfixed_reads += count_nonfixed_reads (loop, PATTERN (p));
 
          /* If the loop has a single store, and the destination address is
             invariant, then we can't reverse the loop, because this address
@@ -7937,7 +8046,10 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
 
              reversible_mem_store
                = (! unknown_address_altered
-                  && ! invariant_p (XEXP (XEXP (loop_store_mems, 0), 0)));
+                  && ! unknown_constant_address_altered
+                  && ! loop_invariant_p (loop,
+                                         XEXP (XEXP (loop_store_mems, 0),
+                                               0)));
 
              /* If the store depends on a register that is set after the
                 store, it depends on the initial value, and is thus not
@@ -7946,7 +8058,7 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
                {
                  if (v->giv_type == DEST_REG
                      && reg_mentioned_p (v->dest_reg,
-                                         XEXP (loop_store_mems, 0))
+                                        PATTERN (first_loop_store_insn)) 
                      && loop_insn_first_p (first_loop_store_insn, v->insn))
                    reversible_mem_store = 0;
                }
@@ -7993,7 +8105,7 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
                  || (GET_CODE (comparison) == LE
                      && no_use_except_counting)))
            {
-             HOST_WIDE_INT add_val, add_adjust, comparison_val;
+             HOST_WIDE_INT add_val, add_adjust, comparison_val = 0;
              rtx initial_value, comparison_value;
              int nonneg = 0;
              enum rtx_code cmp_code;
@@ -8019,7 +8131,7 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
                 ??? If the insns which initialize the comparison value as
                 a whole compute an invariant result, then we could move
                 them out of the loop and proceed with loop reversal.  */
-             if (!invariant_p (comparison_value))
+             if (! loop_invariant_p (loop, comparison_value))
                return 0;
 
              if (GET_CODE (comparison_value) == CONST_INT)
@@ -8058,7 +8170,7 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
                     calculate a giv or has a non-counting use.  */
 #if ! defined (HAVE_decrement_and_branch_until_zero) \
 && defined (HAVE_decrement_and_branch_on_count)
-                 && (! (add_val == 1 && loop_info->vtop
+                 && (! (add_val == 1 && loop->vtop
                         && (bl->biv_count == 0
                             || no_use_except_counting)))
 #endif
@@ -8073,7 +8185,7 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
                  nonneg = 1;
                  cmp_code = GE;
                }
-             else if (add_val == 1 && loop_info->vtop
+             else if (add_val == 1 && loop->vtop
                       && (bl->biv_count == 0
                           || no_use_except_counting))
                {
@@ -8307,7 +8419,6 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
 \f
 /* Verify whether the biv BL appears to be eliminable,
    based on the insns in the loop that refer to it.
-   LOOP_START is the first insn of the loop, and END is the end insn.
 
    If ELIMINATE_P is non-zero, actually do the elimination.
 
@@ -8316,20 +8427,21 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
    start of the loop.  */
 
 static int
-maybe_eliminate_biv (bl, loop_start, end, eliminate_p, threshold, insn_count)
+maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
+     const struct loop *loop;
      struct iv_class *bl;
-     rtx loop_start;
-     rtx end;
      int eliminate_p;
      int threshold, insn_count;
 {
   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 != 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;
@@ -8346,7 +8458,7 @@ maybe_eliminate_biv (bl, loop_start, end, eliminate_p, threshold, insn_count)
 
              if (set && GET_CODE (SET_DEST (set)) == REG)
                {
-                 int regno = REGNO (SET_DEST (set));
+                 unsigned int regno = REGNO (SET_DEST (set));
 
                  if (regno < max_reg_before_loop
                      && REG_IV_TYPE (regno) == GENERAL_INDUCT
@@ -8357,7 +8469,8 @@ maybe_eliminate_biv (bl, loop_start, end, eliminate_p, threshold, insn_count)
        }
       if ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
          && reg_mentioned_p (reg, PATTERN (p))
-         && ! maybe_eliminate_biv_1 (PATTERN (p), p, bl, eliminate_p, where))
+         && ! maybe_eliminate_biv_1 (loop, PATTERN (p), p, bl,
+                                     eliminate_p, where))
        {
          if (loop_dump_stream)
            fprintf (loop_dump_stream,
@@ -8367,7 +8480,7 @@ maybe_eliminate_biv (bl, loop_start, end, eliminate_p, threshold, insn_count)
        }
     }
 
-  if (p == end)
+  if (p == loop_end)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream, "biv %d %s eliminated.\n",
@@ -8461,7 +8574,8 @@ biv_elimination_giv_has_0_offset (biv, giv, insn)
    the loop.  */
 
 static int
-maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
+maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
+     const struct loop *loop;
      rtx x, insn;
      struct iv_class *bl;
      int eliminate_p;
@@ -8680,7 +8794,7 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
        }
       else if (GET_CODE (arg) == REG || GET_CODE (arg) == MEM)
        {
-         if (invariant_p (arg) == 1)
+         if (loop_invariant_p (loop, arg) == 1)
            {
              /* Look for giv with constant positive mult_val and nonconst
                 add_val. Insert insns to compute new compare value. 
@@ -8787,14 +8901,14 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
       switch (fmt[i])
        {
        case 'e':
-         if (! maybe_eliminate_biv_1 (XEXP (x, i), insn, bl, 
+         if (! maybe_eliminate_biv_1 (loop, XEXP (x, i), insn, bl, 
                                       eliminate_p, where))
            return 0;
          break;
 
        case 'E':
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           if (! maybe_eliminate_biv_1 (XVECEXP (x, i, j), insn, bl,
+           if (! maybe_eliminate_biv_1 (loop, XVECEXP (x, i, j), insn, bl,
                                         eliminate_p, where))
              return 0;
          break;
@@ -8827,9 +8941,10 @@ last_use_this_basic_block (reg, insn)
    just record the location of the set and process it later.  */
 
 static void
-record_initial (dest, set)
+record_initial (dest, set, data)
      rtx dest;
      rtx set;
+     void *data ATTRIBUTE_UNUSED;
 {
   struct iv_class *bl;
 
@@ -8881,32 +8996,34 @@ update_reg_last_use (x, insn)
     }
 }
 \f
-/* Given a jump insn JUMP, return the condition that will cause it to branch
-   to its JUMP_LABEL.  If the condition cannot be understood, or is an
-   inequality floating-point comparison which needs to be reversed, 0 will
-   be returned.
-
-   If EARLIEST is non-zero, 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.
-
-   The condition will be returned in a canonical form to simplify testing by
-   callers.  Specifically:
+/* Given an insn INSN and condition COND, return the condition in a
+   canonical form to simplify testing by callers.  Specifically:
 
    (1) The code will always be a comparison operation (EQ, NE, GT, etc.).
    (2) Both operands will be machine operands; (cc0) will have been replaced.
    (3) If an operand is a constant, it will be the second operand.
    (4) (LE x const) will be replaced with (LT x <const+1>) and similarly
-       for GE, GEU, and LEU.  */
+       for GE, GEU, and LEU.
+
+   If the condition cannot be understood, or is an inequality floating-point
+   comparison which needs to be reversed, 0 will be returned.
+
+   If REVERSE is non-zero, then reverse the condition prior to canonizing it.
+
+   If EARLIEST is non-zero, 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.  */
 
 rtx
-get_condition (jump, earliest)
-     rtx jump;
+canonicalize_condition (insn, cond, reverse, earliest)
+     rtx insn;
+     rtx cond;
+     int reverse;
      rtx *earliest;
 {
   enum rtx_code code;
-  rtx prev = jump;
+  rtx prev = insn;
   rtx set;
   rtx tem;
   rtx op0, op1;
@@ -8914,24 +9031,19 @@ get_condition (jump, earliest)
   int did_reverse_condition = 0;
   enum machine_mode mode;
 
-  /* If this is not a standard conditional jump, we can't parse it.  */
-  if (GET_CODE (jump) != JUMP_INSN
-      || ! condjump_p (jump) || simplejump_p (jump))
-    return 0;
+  code = GET_CODE (cond);
+  mode = GET_MODE (cond);
+  op0 = XEXP (cond, 0);
+  op1 = XEXP (cond, 1);
 
-  code = GET_CODE (XEXP (SET_SRC (PATTERN (jump)), 0));
-  mode = GET_MODE (XEXP (SET_SRC (PATTERN (jump)), 0));
-  op0 = XEXP (XEXP (SET_SRC (PATTERN (jump)), 0), 0);
-  op1 = XEXP (XEXP (SET_SRC (PATTERN (jump)), 0), 1);
+  if (reverse)
+    {
+      code = reverse_condition (code);
+      did_reverse_condition ^= 1;
+    }
 
   if (earliest)
-    *earliest = jump;
-
-  /* If this branches to JUMP_LABEL when the condition is false, reverse
-     the condition.  */
-  if (GET_CODE (XEXP (SET_SRC (PATTERN (jump)), 2)) == LABEL_REF
-      && XEXP (XEXP (SET_SRC (PATTERN (jump)), 2), 0) == JUMP_LABEL (jump))
-    code = reverse_condition (code), did_reverse_condition ^= 1;
+    *earliest = insn;
 
   /* If we are comparing a register with zero, see if the register is set
      in the previous insn to a COMPARE or a comparison operation.  Perform
@@ -9013,7 +9125,8 @@ get_condition (jump, earliest)
 #ifdef FLOAT_STORE_FLAG_VALUE
                     || (code == LT
                         && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                        && FLOAT_STORE_FLAG_VALUE < 0)
+                        && (REAL_VALUE_NEGATIVE
+                            (FLOAT_STORE_FLAG_VALUE (inner_mode))))
 #endif
                     ))
                   && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'))
@@ -9032,7 +9145,8 @@ get_condition (jump, earliest)
 #ifdef FLOAT_STORE_FLAG_VALUE
                     || (code == GE
                         && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                        && FLOAT_STORE_FLAG_VALUE < 0)
+                        && (REAL_VALUE_NEGATIVE
+                            (FLOAT_STORE_FLAG_VALUE (inner_mode))))
 #endif
                     ))
                   && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'
@@ -9063,6 +9177,8 @@ get_condition (jump, earliest)
          if (reverse_code)
            {
              code = reverse_condition (code);
+             if (code == UNKNOWN)
+               return 0;
              did_reverse_condition ^= 1;
              reverse_code = 0;
            }
@@ -9127,9 +9243,10 @@ get_condition (jump, earliest)
     }
 
   /* If this was floating-point and we reversed anything other than an
-     EQ or NE, return zero.  */
+     EQ or NE or (UN)ORDERED, return zero.  */
   if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-      && did_reverse_condition && code != NE && code != EQ
+      && did_reverse_condition
+      && code != NE && code != EQ && code != UNORDERED && code != ORDERED
       && ! flag_fast_math
       && GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
     return 0;
@@ -9143,18 +9260,53 @@ get_condition (jump, earliest)
   return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
 }
 
+/* Given a jump insn JUMP, return the condition that will cause it to branch
+   to its JUMP_LABEL.  If the condition cannot be understood, or is an
+   inequality floating-point comparison which needs to be reversed, 0 will
+   be returned.
+
+   If EARLIEST is non-zero, 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.  */
+
+rtx
+get_condition (jump, earliest)
+     rtx jump;
+     rtx *earliest;
+{
+  rtx cond;
+  int reverse;
+
+  /* If this is not a standard conditional jump, we can't parse it.  */
+  if (GET_CODE (jump) != JUMP_INSN
+      || ! condjump_p (jump) || simplejump_p (jump))
+    return 0;
+
+  cond = XEXP (SET_SRC (PATTERN (jump)), 0);
+
+  /* If this branches to JUMP_LABEL when the condition is false, reverse
+     the condition.  */
+  reverse
+    = GET_CODE (XEXP (SET_SRC (PATTERN (jump)), 2)) == LABEL_REF
+      && XEXP (XEXP (SET_SRC (PATTERN (jump)), 2), 0) == JUMP_LABEL (jump);
+
+  return canonicalize_condition (jump, cond, reverse, earliest);
+}
+
 /* Similar to above routine, except that we also put an invariant last
    unless both operands are invariants.  */
 
 rtx
-get_condition_for_loop (x)
+get_condition_for_loop (loop, x)
+     const struct loop *loop;
      rtx x;
 {
   rtx comparison = get_condition (x, NULL_PTR);
 
   if (comparison == 0
-      || ! invariant_p (XEXP (comparison, 0))
-      || invariant_p (XEXP (comparison, 1)))
+      || ! loop_invariant_p (loop, XEXP (comparison, 0))
+      || loop_invariant_p (loop, XEXP (comparison, 1)))
     return comparison;
 
   return gen_rtx_fmt_ee (swap_condition (GET_CODE (comparison)), VOIDmode,
@@ -9169,29 +9321,29 @@ get_condition_for_loop (x)
  */
 
 static void
-insert_bct (loop_start, loop_end, loop_info)
-     rtx loop_start, loop_end;
-     struct loop_info *loop_info;
+insert_bct (loop)
+     struct loop *loop;
 {
-  int i;
   unsigned HOST_WIDE_INT n_iterations;
+  rtx loop_start = loop->start;
+  rtx loop_end = loop->end;
+  struct loop_info *loop_info = LOOP_INFO (loop);  
+  int loop_num = loop->num;
 
+#if 0
   int increment_direction, compare_direction;
-
   /* If the loop condition is <= or >=, the number of iteration
       is 1 more than the range of the bounds of the loop.  */
   int add_iteration = 0;
-
   enum machine_mode loop_var_mode = word_mode;
-
-  int loop_num = uid_loop_num [INSN_UID (loop_start)];
+#endif
 
   /* It's impossible to instrument a competely unrolled loop.  */
   if (loop_info->unroll_number == loop_info->n_iterations)
     return;
 
   /* Make sure that the count register is not in use.  */
-  if (loop_used_count_register [loop_num])
+  if (loop_info->used_count_register)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -9265,9 +9417,15 @@ insert_bct (loop_start, loop_end, loop_info)
   /* Handle the simpler case, where the bounds are known at compile time.  */
   if (n_iterations > 0)
     {
+      struct loop *outer_loop;
+      struct loop_info *outer_loop_info;
+
       /* Mark all enclosing loops that they cannot use count register.  */
-      for (i = loop_num; i != -1; i = loop_outer_loop[i])
-       loop_used_count_register[i] = 1;
+      for (outer_loop = loop; outer_loop; outer_loop = outer_loop->outer)
+       {
+         outer_loop_info = LOOP_INFO (outer_loop);
+         outer_loop_info->used_count_register = 1;
+       }
       instrument_loop_bct (loop_start, loop_end, GEN_INT (n_iterations));
       return;
     }
@@ -9475,11 +9633,19 @@ insert_loop_mem (mem, data)
     case MEM:
       break;
 
+    case CLOBBER:
+      /* We're not interested in MEMs that are only clobbered.  */
+      return -1;
+
     case CONST_DOUBLE:
       /* We're not interested in the MEM associated with a
         CONST_DOUBLE, so there's no need to traverse into this.  */
       return -1;
 
+    case EXPR_LIST:
+      /* We're not interested in any MEMs that only appear in notes.  */
+      return -1;
+
     default:
       /* This is not a MEM.  */
       return 0;
@@ -9529,17 +9695,13 @@ insert_loop_mem (mem, data)
    values after load_mems.  */
 
 static void
-load_mems_and_recount_loop_regs_set (scan_start, end, loop_top, start,
-                                    insn_count)
-     rtx scan_start;
-     rtx end;
-     rtx loop_top;
-     rtx start;
+load_mems_and_recount_loop_regs_set (loop, insn_count)
+     const struct loop *loop;
      int *insn_count;
 {
   int nregs = max_reg_num ();
 
-  load_mems (scan_start, end, loop_top, start);
+  load_mems (loop);
   
   /* Recalculate set_in_loop and friends since load_mems may have
      created new registers.  */
@@ -9564,7 +9726,7 @@ load_mems_and_recount_loop_regs_set (scan_start, end, loop_top, start,
       bzero ((char *) &may_not_optimize->data, nregs * sizeof (char));
       bzero ((char *) &reg_single_usage->data, nregs * sizeof (rtx));
 
-      count_loop_regs_set (loop_top ? loop_top : start, end,
+      count_loop_regs_set (loop->top ? loop->top : loop->start, loop->end,
                           may_not_optimize, reg_single_usage,
                           insn_count, nregs); 
 
@@ -9589,182 +9751,267 @@ load_mems_and_recount_loop_regs_set (scan_start, end, loop_top, start,
     }
 }
 
-/* Move MEMs into registers for the duration of the loop.  SCAN_START
-   is the first instruction in the loop (as it is executed).  The
-   other parameters are as for next_insn_in_loop.  */
+/* Move MEMs into registers for the duration of the loop.  */
 
 static void
-load_mems (scan_start, end, loop_top, start)
-     rtx scan_start;
-     rtx end;
-     rtx loop_top;
-     rtx start;
+load_mems (loop)
+     const struct loop *loop;
 {
   int maybe_never = 0;
   int i;
   rtx p;
   rtx label = NULL_RTX;
   rtx end_label = NULL_RTX;
+  /* Nonzero if the next instruction may never be executed.  */
+  int next_maybe_never = 0;
+  int last_max_reg = max_reg_num ();
 
-  if (loop_mems_idx > 0) 
-    {
-      /* Nonzero if the next instruction may never be executed.  */
-      int next_maybe_never = 0;
+  if (loop_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 ();
 
-      /* Check to see if it's possible that some instructions in the
-        loop are never executed.  */
-      for (p = next_insn_in_loop (scan_start, scan_start, end, loop_top); 
-          p != NULL_RTX && !maybe_never; 
-          p = next_insn_in_loop (p, scan_start, end, loop_top))
+  /* 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.  */
+  for (p = next_insn_in_loop (loop, loop->scan_start); 
+       p != NULL_RTX && ! maybe_never; 
+       p = next_insn_in_loop (loop, p))
+    {
+      if (GET_CODE (p) == CODE_LABEL)
+       maybe_never = 1;
+      else if (GET_CODE (p) == JUMP_INSN
+              /* If we enter the loop in the middle, and scan
+                 around to the 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
+                    && NEXT_INSN (NEXT_INSN (p)) == loop->end
+                    && simplejump_p (p)))
        {
-         if (GET_CODE (p) == CODE_LABEL)
+         if (!condjump_p (p))
+           /* Something complicated.  */
            maybe_never = 1;
-         else if (GET_CODE (p) == JUMP_INSN
-                  /* If we enter the loop in the middle, and scan
-                     around to the 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
-                        && NEXT_INSN (NEXT_INSN (p)) == end
-                        && simplejump_p (p)))
+         else
+           /* If there are any more instructions in the loop, they
+              might not be reached.  */
+           next_maybe_never = 1; 
+       } 
+      else if (next_maybe_never)
+       maybe_never = 1;
+    }
+
+  /* Actually move the MEMs.  */
+  for (i = 0; i < loop_mems_idx; ++i) 
+    {
+      regset_head copies;
+      int written = 0;
+      rtx reg;
+      rtx mem = loop_mems[i].mem;
+      rtx mem_list_entry;
+
+      if (MEM_VOLATILE_P (mem) 
+         || loop_invariant_p (loop, XEXP (mem, 0)) != 1)
+       /* There's no telling whether or not MEM is modified.  */
+       loop_mems[i].optimize = 0;
+
+      /* Go through the MEMs written to in the loop to see if this
+        one is aliased by one of them.  */
+      mem_list_entry = loop_store_mems;
+      while (mem_list_entry)
+       {
+         if (rtx_equal_p (mem, XEXP (mem_list_entry, 0)))
+           written = 1;
+         else if (true_dependence (XEXP (mem_list_entry, 0), VOIDmode,
+                                   mem, rtx_varies_p))
            {
-             if (!condjump_p (p))
-               /* Something complicated.  */
-               maybe_never = 1;
-             else
-               /* If there are any more instructions in the loop, they
-                  might not be reached.  */
-               next_maybe_never = 1; 
-           } 
-         else if (next_maybe_never)
-           maybe_never = 1;
+             /* MEM is indeed aliased by this store.  */
+             loop_mems[i].optimize = 0;
+             break;
+           }
+         mem_list_entry = XEXP (mem_list_entry, 1);
        }
 
-      /* Actually move the MEMs.  */
-      for (i = 0; i < loop_mems_idx; ++i) 
+      if (flag_float_store && written
+         && GET_MODE_CLASS (GET_MODE (mem)) == MODE_FLOAT)
+       loop_mems[i].optimize = 0;
+  
+      /* If this MEM is written to, we must be sure that there
+        are no reads from another MEM that aliases this one.  */ 
+      if (loop_mems[i].optimize && written)
        {
-         int written = 0;
-         rtx reg;
-         rtx mem = loop_mems[i].mem;
-         rtx mem_list_entry;
-
-         if (MEM_VOLATILE_P (mem) 
-             || invariant_p (XEXP (mem, 0)) != 1)
-           /* There's no telling whether or not MEM is modified.  */
-           loop_mems[i].optimize = 0;
-
-         /* Go through the MEMs written to in the loop to see if this
-            one is aliased by one of them.  */
-         mem_list_entry = loop_store_mems;
-         while (mem_list_entry)
+         int j;
+
+         for (j = 0; j < loop_mems_idx; ++j)
            {
-             if (rtx_equal_p (mem, XEXP (mem_list_entry, 0)))
-               written = 1;
-             else if (true_dependence (XEXP (mem_list_entry, 0), VOIDmode,
-                                       mem, rtx_varies_p))
+             if (j == i)
+               continue;
+             else if (true_dependence (mem,
+                                       VOIDmode,
+                                       loop_mems[j].mem,
+                                       rtx_varies_p))
                {
-                 /* MEM is indeed aliased by this store.  */
+                 /* It's not safe to hoist loop_mems[i] out of
+                    the loop because writes to it might not be
+                    seen by reads from loop_mems[j].  */
                  loop_mems[i].optimize = 0;
                  break;
                }
-             mem_list_entry = XEXP (mem_list_entry, 1);
-           }
-         
-         /* If this MEM is written to, we must be sure that there
-            are no reads from another MEM that aliases this one.  */ 
-         if (loop_mems[i].optimize && written)
-           {
-             int j;
-
-             for (j = 0; j < loop_mems_idx; ++j)
-               {
-                 if (j == i)
-                   continue;
-                 else if (true_dependence (mem,
-                                           VOIDmode,
-                                           loop_mems[j].mem,
-                                           rtx_varies_p))
-                   {
-                     /* It's not safe to hoist loop_mems[i] out of
-                        the loop because writes to it might not be
-                        seen by reads from loop_mems[j].  */
-                     loop_mems[i].optimize = 0;
-                     break;
-                   }
-               }
            }
+       }
 
-         if (maybe_never && may_trap_p (mem))
-           /* We can't access the MEM outside the loop; it might
-              cause a trap that wouldn't have happened otherwise.  */
-           loop_mems[i].optimize = 0;
+      if (maybe_never && may_trap_p (mem))
+       /* We can't access the MEM outside the loop; it might
+          cause a trap that wouldn't have happened otherwise.  */
+       loop_mems[i].optimize = 0;
          
-         if (!loop_mems[i].optimize)
-           /* We thought we were going to lift this MEM out of the
-              loop, but later discovered that we could not.  */
-           continue;
+      if (!loop_mems[i].optimize)
+       /* We thought we were going to lift this MEM out of the
+          loop, but later discovered that we could not.  */
+       continue;
 
-         /* Allocate a pseudo for this MEM.  We set REG_USERVAR_P in
-            order to keep scan_loop from moving stores to this MEM
-            out of the loop just because this REG is neither a
-            user-variable nor used in the loop test.  */
-         reg = gen_reg_rtx (GET_MODE (mem));
-         REG_USERVAR_P (reg) = 1;
-         loop_mems[i].reg = reg;
-
-         /* Now, replace all references to the MEM with the
-            corresponding pesudos.  */
-         for (p = next_insn_in_loop (scan_start, scan_start, end, loop_top);
-              p != NULL_RTX;
-              p = next_insn_in_loop (p, scan_start, end, loop_top))
+      INIT_REG_SET (&copies);
+
+      /* Allocate a pseudo for this MEM.  We set REG_USERVAR_P in
+        order to keep scan_loop from moving stores to this MEM
+        out of the loop just because this REG is neither a
+        user-variable nor used in the loop test.  */
+      reg = gen_reg_rtx (GET_MODE (mem));
+      REG_USERVAR_P (reg) = 1;
+      loop_mems[i].reg = reg;
+
+      /* Now, replace all references to the MEM with the
+        corresponding pesudos.  */
+      maybe_never = 0;
+      for (p = next_insn_in_loop (loop, loop->scan_start);
+          p != NULL_RTX;
+          p = next_insn_in_loop (loop, p))
+       {
+         rtx_and_int ri;
+         rtx set;
+
+         if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
            {
-             rtx_and_int ri;
+             /* See if this copies the mem into a register that isn't
+                modified afterwards.  We'll try to do copy propagation
+                a little further on.  */
+             set = single_set (p);
+             if (set
+                 /* @@@ This test is _way_ too conservative.  */
+                 && ! maybe_never
+                 && GET_CODE (SET_DEST (set)) == REG
+                 && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
+                 && REGNO (SET_DEST (set)) < last_max_reg
+                 && VARRAY_INT (n_times_set, REGNO (SET_DEST (set))) == 1
+                 && rtx_equal_p (SET_SRC (set), loop_mems[i].mem))
+               SET_REGNO_REG_SET (&copies, REGNO (SET_DEST (set)));
              ri.r = p;
              ri.i = i;
              for_each_rtx (&p, replace_loop_mem, &ri);
            }
 
-         if (!apply_change_group ())
-           /* We couldn't replace all occurrences of the MEM.  */
-           loop_mems[i].optimize = 0;
-         else
-           {
-             rtx set;
-
-             /* Load the memory immediately before START, which is
-                the NOTE_LOOP_BEG.  */
-             set = gen_move_insn (reg, mem);
-             emit_insn_before (set, start);
+         if (GET_CODE (p) == CODE_LABEL
+             || GET_CODE (p) == JUMP_INSN)
+           maybe_never = 1;
+       }
 
-             if (written)
+      if (! apply_change_group ())
+       /* We couldn't replace all occurrences of the MEM.  */
+       loop_mems[i].optimize = 0;
+      else
+       {
+         /* Load the memory immediately before LOOP->START, which is
+            the NOTE_LOOP_BEG.  */
+         cselib_val *e = cselib_lookup (mem, VOIDmode, 0);
+         rtx set;
+         rtx best = mem;
+         int j;
+         struct elt_loc_list *const_equiv = 0;
+
+         if (e)
+           {
+             struct elt_loc_list *equiv;
+             struct elt_loc_list *best_equiv = 0;
+             for (equiv = e->locs; equiv; equiv = equiv->next)
                {
-                 if (label == NULL_RTX)
-                   {
-                     /* We must compute the former
-                        right-after-the-end label before we insert
-                        the new one.  */
-                     end_label = next_label (end);
-                     label = gen_label_rtx ();
-                     emit_label_after (label, end);
-                   }
-
-                 /* 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);
+                 if (CONSTANT_P (equiv->loc))
+                   const_equiv = equiv;
+                 else if (GET_CODE (equiv->loc) == REG)
+                   best_equiv = equiv;
+               }
+             /* Use the constant equivalence if that is cheap enough.  */
+             if (! best_equiv)
+               best_equiv = const_equiv;
+             else if (const_equiv
+                      && (rtx_cost (const_equiv->loc, SET)
+                          <= rtx_cost (best_equiv->loc, SET)))
+               {
+                 best_equiv = const_equiv;
+                 const_equiv = 0;
                }
 
-             if (loop_dump_stream)
+             /* If best_equiv is nonzero, we know that MEM is set to a
+                constant or register before the loop.  We will use this
+                knowledge to initialize the shadow register with that
+                constant or reg rather than by loading from MEM.  */
+             if (best_equiv)
+               best = copy_rtx (best_equiv->loc);
+           }
+         set = gen_move_insn (reg, best);
+         set = emit_insn_before (set, loop->start);
+         if (const_equiv)
+           REG_NOTES (set) = gen_rtx_EXPR_LIST (REG_EQUAL,
+                                                copy_rtx (const_equiv->loc),
+                                                REG_NOTES (set));
+
+         if (written)
+           {
+             if (label == NULL_RTX)
                {
-                 fprintf (loop_dump_stream, "Hoisted regno %d %s from ",
-                          REGNO (reg), (written ? "r/w" : "r/o"));
-                 print_rtl (loop_dump_stream, mem);
-                 fputc ('\n', loop_dump_stream);
+                 /* 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);
                }
+
+             /* 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);
            }
+
+         if (loop_dump_stream)
+           {
+             fprintf (loop_dump_stream, "Hoisted regno %d %s from ",
+                      REGNO (reg), (written ? "r/w" : "r/o"));
+             print_rtl (loop_dump_stream, mem);
+             fputc ('\n', loop_dump_stream);
+           }
+
+         /* Attempt a bit of copy propagation.  This helps untangle the
+            data flow, and enables {basic,general}_induction_var to find
+            more bivs/givs.  */
+         EXECUTE_IF_SET_IN_REG_SET
+           (&copies, FIRST_PSEUDO_REGISTER, j,
+            {
+              try_copy_prop (loop, loop_mems[i].reg, j);
+            });
+         CLEAR_REG_SET (&copies);
        }
     }
 
@@ -9776,7 +10023,7 @@ load_mems (scan_start, end, loop_top, start)
       rr.r1 = end_label;
       rr.r2 = label;
 
-      for (p = start; p != end; p = NEXT_INSN (p))
+      for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
        {
          for_each_rtx (&p, replace_label, &rr);
 
@@ -9790,6 +10037,114 @@ load_mems (scan_start, end, loop_top, start)
            JUMP_LABEL (p) = label;
        }
     }
+
+  cselib_finish ();
+}
+
+/* For communication between note_reg_stored and its caller.  */
+struct note_reg_stored_arg
+{
+  int set_seen;
+  rtx reg;
+};
+
+/* Called via note_stores, record in SET_SEEN whether X, which is written,
+   is equal to ARG.  */
+static void
+note_reg_stored (x, setter, arg)
+     rtx x, setter ATTRIBUTE_UNUSED;
+     void *arg;
+{
+  struct note_reg_stored_arg *t = (struct note_reg_stored_arg *)arg;
+  if (t->reg == x)
+    t->set_seen = 1;
+}
+
+/* Try to replace every occurrence of pseudo REGNO with REPLACEMENT.
+   There must be exactly one insn that sets this pseudo; it will be
+   deleted if all replacements succeed and we can prove that the register
+   is not used after the loop.  */
+
+static void
+try_copy_prop (loop, replacement, regno)
+     const struct loop *loop;
+     rtx replacement;
+     unsigned int regno;
+{
+  /* This is the reg that we are copying from.  */
+  rtx reg_rtx = regno_reg_rtx[regno];
+  rtx init_insn = 0;
+  rtx insn;
+  /* These help keep track of whether we replaced all uses of the reg.  */
+  int replaced_last = 0;
+  int store_is_first = 0;
+
+  for (insn = next_insn_in_loop (loop, loop->scan_start);
+       insn != NULL_RTX;
+       insn = next_insn_in_loop (loop, insn))
+    {
+      rtx set;
+
+      /* Only substitute within one extended basic block from the initializing
+         insn.  */
+      if (GET_CODE (insn) == CODE_LABEL && init_insn)
+       break;
+
+      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+       continue;
+
+      /* Is this the initializing insn?  */
+      set = single_set (insn);
+      if (set
+         && GET_CODE (SET_DEST (set)) == REG
+         && REGNO (SET_DEST (set)) == regno)
+       {
+         if (init_insn)
+           abort ();
+
+         init_insn = insn;
+         if (REGNO_FIRST_UID (regno) == INSN_UID (insn))
+           store_is_first = 1;
+       }
+
+      /* Only substitute after seeing the initializing insn.  */
+      if (init_insn && insn != init_insn)
+       {       
+         struct note_reg_stored_arg arg;
+         rtx array[3];
+         array[0] = reg_rtx;
+         array[1] = replacement;
+         array[2] = insn;
+
+         for_each_rtx (&insn, replace_loop_reg, array);
+         if (REGNO_LAST_UID (regno) == INSN_UID (insn))
+           replaced_last = 1;
+
+         /* Stop replacing when REPLACEMENT is modified.  */
+         arg.reg = replacement;
+         arg.set_seen = 0;
+         note_stores (PATTERN (insn), note_reg_stored, &arg);
+         if (arg.set_seen)
+           break;
+       }
+    }
+  if (! init_insn)
+    abort ();
+  if (apply_change_group ())
+    {
+      if (loop_dump_stream)
+       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));
+       }
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream, ".\n");
+    }
 }
 
 /* Replace MEM with its associated pseudo register.  This function is
@@ -9840,6 +10195,28 @@ replace_loop_mem (mem, data)
   return 0;
 }
 
+/* Replace one register with another.  Called through for_each_rtx; PX points
+   to the rtx being scanned.  DATA is actually an array of three rtx's; the
+   first one is the one to be replaced, and the second one the replacement.
+   The third one is the current insn.  */
+
+static int
+replace_loop_reg (px, data)
+     rtx *px;
+     void *data;
+{
+  rtx x = *px;
+  rtx *array = (rtx *)data;
+
+  if (x == NULL_RTX)
+    return 0;
+
+  if (x == array[0])
+    validate_change (array[2], px, array[1], 1);
+
+  return 0;
+}
+
 /* 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.  */
@@ -9868,4 +10245,3 @@ replace_label (x, data)
 
   return 0;
 }
-