OSDN Git Service

libiberty:
[pf3gnuchains/gcc-fork.git] / gcc / loop.c
index c5e5c4c..7eb4d0d 100644 (file)
@@ -1,6 +1,6 @@
 /* Perform various loop optimizations, including strength reduction.
    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -54,6 +54,14 @@ Boston, MA 02111-1307, USA.  */
 #include "except.h"
 #include "toplev.h"
 
+#define LOOP_REG_LIFETIME(LOOP, REGNO) \
+((REGNO_LAST_LUID (REGNO) - REGNO_FIRST_LUID (REGNO)))
+
+#define LOOP_REG_GLOBAL_P(LOOP, REGNO) \
+((REGNO_LAST_LUID (REGNO) > INSN_LUID ((LOOP)->end) \
+ || REGNO_FIRST_LUID (REGNO) < INSN_LUID ((LOOP)->start)))
+
+
 /* 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.  */
@@ -78,87 +86,6 @@ static int max_luid;
 
 static int max_loop_num;
 
-/* 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
-   made a candidate; in particular -2 means that it is an candidate that
-   we know is equal to a constant and -1 means that it is an candidate
-   not known equal to a constant.
-   After code motion, regs moved have 0 (which is accurate now)
-   while the failed candidates have the original number of times set.
-
-   Therefore, at all times, == 0 indicates an invariant register;
-   < 0 a conditionally invariant one.  */
-
-static varray_type set_in_loop;
-
-/* Original value of set_in_loop; same except that this value
-   is not set negative for a reg whose sets have been made candidates
-   and not set to 0 for a reg that is moved.  */
-
-static varray_type n_times_set;
-
-/* Index by register number, 1 indicates that the register
-   cannot be moved or strength reduced.  */
-
-static varray_type may_not_optimize;
-
-/* Contains the insn in which a register was used if it was used
-   exactly once; contains const0_rtx if it was used more than once.  */
-
-static varray_type reg_single_usage;
-
-/* Nonzero means reg N has already been moved out of one loop.
-   This reduces the desire to move it out of another.  */
-
-static char *moved_once;
-
-/* List of MEMs that are stored in this loop.  */
-
-static rtx loop_store_mems;
-
-/* The insn where the first of these was found.  */
-static rtx first_loop_store_insn;
-
-typedef struct loop_mem_info {
-  rtx mem;      /* The MEM itself.  */
-  rtx reg;      /* Corresponding pseudo, if any.  */
-  int optimize; /* Nonzero if we can optimize access to this MEM.  */
-} loop_mem_info;
-
-/* Array of MEMs that are used (read or written) in this loop, but
-   cannot be aliased by anything in this loop, except perhaps
-   themselves.  In other words, if loop_mems[i] is altered during the
-   loop, it is altered by an expression that is rtx_equal_p to it.  */
-
-static loop_mem_info *loop_mems;
-
-/* The index of the next available slot in LOOP_MEMS.  */
-
-static int loop_mems_idx;
-
-/* The number of elements allocated in LOOP_MEMs.  */
-
-static int loop_mems_allocated;
-
-/* Nonzero if we don't know what MEMs were changed in the current
-   loop.  This happens if the loop contains a call (in which case
-   `loop_info->has_call' will also be set) or if we store into more
-   than NUM_STORES MEMs.  */
-
-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;
-
-/* Count of memory write instructions discovered in the loop.  */
-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.  */
 unsigned int max_reg_before_loop;
@@ -166,17 +93,6 @@ unsigned int max_reg_before_loop;
 /* The value to pass to the next call of reg_scan_update.  */
 static int loop_max_reg;
 
-/* This obstack is used in product_cheap_p to allocate its rtl.  It
-   may call gen_reg_rtx which, in turn, may reallocate regno_reg_rtx.
-   If we used the same obstack that it did, we would be deallocating
-   that array.  */
-
-static struct obstack temp_obstack;
-
-/* This is where the pointer to the obstack being used for RTL is stored.  */
-
-extern struct obstack *rtl_obstack;
-
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 \f
@@ -224,13 +140,11 @@ struct movable
   struct movable *next;
 };
 
-static struct movable *the_movables;
 
 FILE *loop_dump_stream;
 
 /* Forward declarations.  */
 
-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 *));
@@ -238,11 +152,7 @@ static int reg_in_basic_block_p PARAMS ((rtx, rtx));
 static int consec_sets_invariant_p PARAMS ((const struct loop *,
                                            rtx, int, rtx));
 static int labels_in_range_p PARAMS ((rtx, int));
-static void count_one_set PARAMS ((rtx, rtx, varray_type, rtx *));
-
-static void count_loop_regs_set PARAMS ((const struct loop*,
-                                        varray_type, varray_type,
-                                        int *, int));
+static void count_one_set PARAMS ((struct loop_regs *, rtx, rtx, rtx *));
 static void note_addr_stored PARAMS ((rtx, rtx, void *));
 static void note_set_pseudo_multiple_uses PARAMS ((rtx, rtx, void *));
 static int loop_reg_used_before_p PARAMS ((const struct loop *, rtx, rtx));
@@ -252,59 +162,84 @@ static void replace_call_address PARAMS ((rtx, rtx, rtx));
 #endif
 static rtx skip_consec_insns PARAMS ((rtx, int));
 static int libcall_benefit PARAMS ((rtx));
-static void ignore_some_movables PARAMS ((struct 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 ignore_some_movables PARAMS ((struct loop_movables *));
+static void force_movables PARAMS ((struct loop_movables *));
+static void combine_movables PARAMS ((struct loop_movables *,
+                                     struct loop_regs *));
+static int regs_match_p PARAMS ((rtx, rtx, struct loop_movables *));
+static int rtx_equal_for_loop_p PARAMS ((rtx, rtx, struct loop_movables *,
+                                        struct loop_regs *));
 static void add_label_notes PARAMS ((rtx, rtx));
-static void move_movables PARAMS ((struct loop *loop, struct movable *,
-                                  int, int, int));
+static void move_movables PARAMS ((struct loop *loop, struct loop_movables *,
+                                  int, int));
+static void loop_movables_add PARAMS((struct loop_movables *,
+                                     struct movable *));
+static void loop_movables_free PARAMS((struct loop_movables *));
 static int count_nonfixed_reads PARAMS ((const struct loop *, rtx));
+static void loop_bivs_find PARAMS((struct loop *));
+static void loop_bivs_init_find PARAMS((struct loop *));
+static void loop_bivs_check PARAMS((struct loop *));
+static void loop_givs_find PARAMS((struct loop *));
+static void loop_givs_check PARAMS((struct loop *));
+static int loop_biv_eliminable_p PARAMS((struct loop *, struct iv_class *,
+                                        int, int));
+static int loop_giv_reduce_benefit PARAMS((struct loop *, struct iv_class *,
+                                          struct induction *, rtx));
+static void loop_givs_dead_check PARAMS((struct loop *, struct iv_class *));
+static void loop_givs_reduce PARAMS((struct loop *, struct iv_class *));
+static void loop_givs_rescan PARAMS((struct loop *, struct iv_class *,
+                                    rtx *));
+static void loop_ivs_free PARAMS((struct loop *));
 static void strength_reduce PARAMS ((struct loop *, int, int));
-static void find_single_use_in_loop PARAMS ((rtx, rtx, varray_type));
+static void find_single_use_in_loop PARAMS ((struct loop_regs *, rtx, rtx));
 static int valid_initial_value_p PARAMS ((rtx, rtx, int, rtx));
 static void find_mem_givs PARAMS ((const struct loop *, rtx, rtx, int, int));
-static void record_biv PARAMS ((struct induction *, rtx, rtx, rtx, rtx, rtx *,
+static void record_biv PARAMS ((struct loop *, struct induction *,
+                               rtx, rtx, rtx, rtx, rtx *,
                                int, int));
 static void check_final_value PARAMS ((const struct loop *,
                                       struct induction *));
+static void loop_ivs_dump PARAMS((const struct loop *, FILE *, int));
+static void loop_iv_class_dump PARAMS((const struct iv_class *, FILE *, int));
+static void loop_biv_dump PARAMS((const struct induction *, FILE *, int));
+static void loop_giv_dump PARAMS((const struct induction *, FILE *, int));
 static void record_giv PARAMS ((const struct loop *, struct induction *,
-                               rtx, rtx, rtx, rtx, rtx, int, enum g_types,
-                               int, int, rtx *));
+                               rtx, rtx, rtx, rtx, rtx, rtx, int,
+                               enum g_types, int, int, rtx *));
 static void update_giv_derive PARAMS ((const struct loop *, rtx));
+static void check_ext_dependant_givs PARAMS ((struct iv_class *,
+                                             struct loop_info *));
 static int basic_induction_var PARAMS ((const struct loop *, rtx,
                                        enum machine_mode, rtx, rtx,
                                        rtx *, rtx *, rtx **));
-static rtx simplify_giv_expr PARAMS ((const struct loop *, rtx, int *));
+static rtx simplify_giv_expr PARAMS ((const struct loop *, rtx, rtx *, int *));
 static int general_induction_var PARAMS ((const struct loop *loop, rtx, rtx *,
-                                         rtx *, rtx *, int, int *, enum machine_mode));
+                                         rtx *, rtx *, rtx *, int, int *,
+                                         enum machine_mode));
 static int consec_sets_giv PARAMS ((const struct loop *, int, rtx,
-                                   rtx, rtx, rtx *, rtx *, rtx *));
+                                   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 PARAMS ((rtx, struct recombine_givs_stats *,
-                                 rtx, rtx));
-static void recombine_givs PARAMS ((const struct loop *, struct iv_class *,
-                                   int));
+static int cmp_combine_givs_stats PARAMS ((const PTR, const PTR));
+static void combine_givs PARAMS ((struct loop_regs *, struct iv_class *));
 static int product_cheap_p PARAMS ((rtx, rtx));
 static int maybe_eliminate_biv PARAMS ((const struct loop *, struct iv_class *,
                                        int, int, int));
 static int maybe_eliminate_biv_1 PARAMS ((const struct loop *, rtx, rtx,
-                                         struct iv_class *, int, rtx));
+                                         struct iv_class *, int,
+                                         basic_block, rtx));
 static int last_use_this_basic_block PARAMS ((rtx, rtx));
 static void record_initial PARAMS ((rtx, rtx, void *));
 static void update_reg_last_use PARAMS ((rtx, rtx));
 static rtx next_insn_in_loop PARAMS ((const struct loop *, rtx));
-static void load_mems_and_recount_loop_regs_set PARAMS ((const struct loop*,
-                                                        int *));
+static void loop_regs_scan PARAMS ((const struct loop*, int, 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 void replace_loop_mems PARAMS ((rtx, rtx, rtx));
 static int replace_loop_reg PARAMS ((rtx *, void *));
+static void replace_loop_regs PARAMS ((rtx insn, rtx, rtx));
 static void note_reg_stored PARAMS ((rtx, rtx, void *));
 static void try_copy_prop PARAMS ((const struct loop *, rtx, unsigned int));
 static void try_swap_copy_prop PARAMS ((const struct loop *, rtx,
@@ -312,20 +247,38 @@ static void try_swap_copy_prop PARAMS ((const struct loop *, rtx,
 static int replace_label PARAMS ((rtx *, void *));
 static rtx check_insn_for_givs PARAMS((struct loop *, rtx, int, int));
 static rtx check_insn_for_bivs PARAMS((struct loop *, rtx, int, int));
+static rtx gen_add_mult PARAMS ((rtx, rtx, rtx, rtx));
+static void loop_regs_update PARAMS ((const struct loop *, rtx));
+static int iv_add_mult_cost PARAMS ((rtx, rtx, rtx, rtx));
+
+static rtx loop_insn_emit_after PARAMS((const struct loop *, basic_block, 
+                                       rtx, rtx));
+static rtx loop_call_insn_emit_before PARAMS((const struct loop *,
+                                             basic_block, rtx, rtx));
+static rtx loop_call_insn_hoist PARAMS((const struct loop *, rtx));
+static rtx loop_insn_sink_or_swim PARAMS((const struct loop *, rtx));
 
 static void loop_dump_aux PARAMS ((const struct loop *, FILE *, int));
+void debug_ivs PARAMS ((const struct loop *));
+void debug_iv_class PARAMS ((const struct iv_class *));
+void debug_biv PARAMS ((const struct induction *));
+void debug_giv PARAMS ((const struct induction *));
 void debug_loop PARAMS ((const struct loop *));
+void debug_loops PARAMS ((const struct loops *));
 
-typedef struct rtx_and_int {
-  rtx r;
-  int i;
-} rtx_and_int;
-
-typedef struct rtx_pair {
+typedef struct rtx_pair
+{
   rtx r1;
   rtx r2;
 } rtx_pair;
 
+typedef struct loop_replace_args
+{
+  rtx match;
+  rtx replacement;
+  rtx insn;
+} loop_replace_args;
+
 /* Nonzero iff INSN is between START and END, inclusive.  */
 #define INSN_IN_RANGE_P(INSN, START, END)      \
   (INSN_UID (INSN) < max_uid_for_loop          \
@@ -339,15 +292,9 @@ static int indirect_jump_in_function_p PARAMS ((rtx));
 static int compute_luids PARAMS ((rtx, rtx, int));
 
 static int biv_elimination_giv_has_0_offset PARAMS ((struct induction *,
-                                                  struct induction *, rtx));
+                                                    struct induction *,
+                                                    rtx));
 \f
-/* Relative gain of eliminating various kinds of operations.  */
-static int add_cost;
-#if 0
-static int shift_cost;
-static int mult_cost;
-#endif
-
 /* Benefit penalty, if a giv is not replaceable, i.e. must emit an insn to
    copy the value of the strength reduced giv to its original register.  */
 static int copy_cost;
@@ -358,24 +305,11 @@ static int reg_address_cost;
 void
 init_loop ()
 {
-  char *free_point = (char *) oballoc (1);
   rtx reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
 
-  add_cost = rtx_cost (gen_rtx_PLUS (word_mode, reg, reg), SET);
-
   reg_address_cost = address_cost (reg, SImode);
 
-  /* We multiply by 2 to reconcile the difference in scale between
-     these two ways of computing costs.  Otherwise the cost of a copy
-     will be far less than the cost of an add.  */
-
-  copy_cost = 2 * 2;
-
-  /* Free the objects we just allocated.  */
-  obfree (free_point);
-
-  /* Initialize the obstack used for rtl in product_cheap_p.  */
-  gcc_obstack_init (&temp_obstack);
+  copy_cost = COSTS_N_INSNS (1);
 }
 \f
 /* Compute the mapping from uids to luids.
@@ -450,8 +384,6 @@ loop_optimize (f, dumpfile, flags)
 
   loops->num = max_loop_num;
 
-  moved_once = (char *) xcalloc (max_reg_before_loop, sizeof (char));
-
   /* Get size to use for tables indexed by uids.
      Leave some space for labels allocated by find_and_verify_loops.  */
   max_uid_for_loop = get_max_uid () + 1 + max_loop_num * 32;
@@ -536,7 +468,6 @@ loop_optimize (f, dumpfile, flags)
   end_alias_analysis ();
 
   /* Clean up.  */
-  free (moved_once);
   free (uid_luid);
   free (uid_loop);
   free (loops_info);
@@ -586,13 +517,11 @@ scan_loop (loop, flags)
      struct loop *loop;
      int flags;
 {
+  struct loop_info *loop_info = LOOP_INFO (loop);
+  struct loop_regs *regs = LOOP_REGS (loop);
   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;
@@ -608,9 +537,7 @@ scan_loop (loop, flags)
   /* The SET from an insn, if it is the only SET in the insn.  */
   rtx set, set1;
   /* Chain describing insns movable in current loop.  */
-  struct movable *movables = 0;
-  /* Last element in `movables' -- so we can add elements at the end.  */
-  struct movable *last_movable = 0;
+  struct loop_movables *movables = LOOP_MOVABLES (loop);
   /* Ratio of extra register life span we can justify
      for saving an instruction.  More if loop doesn't call subroutines
      since in that case saving an insn makes more difference
@@ -618,10 +545,13 @@ scan_loop (loop, flags)
   int threshold;
   /* Nonzero if we are scanning instructions in a sub-loop.  */
   int loop_depth = 0;
-  int nregs;
 
   loop->top = 0;
 
+  movables->head = 0;
+  movables->last = 0;
+  movables->num = 0;
+
   /* Determine whether this loop starts with a jump down to a test at
      the end.  This will occur for a small number of loops with a test
      that is too complex to duplicate in front of the loop.
@@ -649,6 +579,15 @@ scan_loop (loop, flags)
 
   loop->scan_start = p;
 
+  /* If loop end is the end of the current function, then emit a
+     NOTE_INSN_DELETED after loop_end and set loop->sink to the dummy
+     note insn.  This is the position we use when sinking insns out of
+     the loop.  */
+  if (NEXT_INSN (loop->end) != 0)
+    loop->sink = NEXT_INSN (loop->end);
+  else
+    loop->sink = emit_note_after (NOTE_INSN_DELETED, loop->end);
+
   /* Set up variables describing this loop.  */
   prescan_loop (loop);
   threshold = (loop_info->has_call ? 1 : 2) * (1 + n_non_fixed_regs);
@@ -695,40 +634,10 @@ scan_loop (loop, flags)
       return;
     }
 
-  /* Count number of times each reg is set during this loop.
-     Set VARRAY_CHAR (may_not_optimize, I) if it is not safe to move out
-     the setting of register I.  Set VARRAY_RTX (reg_single_usage, I).  */
-
-  /* Allocate extra space for REGS that might be created by
-     load_mems.  We allocate a little extra slop as well, in the hopes
-     that even after the moving of movables creates some new registers
-     we won't have to reallocate these arrays.  However, we do grow
-     the arrays, if necessary, in load_mems_recount_loop_regs_set.  */
-  nregs = max_reg_num () + loop_mems_idx + 16;
-  VARRAY_INT_INIT (set_in_loop, nregs, "set_in_loop");
-  VARRAY_INT_INIT (n_times_set, nregs, "n_times_set");
-  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, may_not_optimize, reg_single_usage, 
-                      &insn_count, nregs);
-
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      VARRAY_CHAR (may_not_optimize, i) = 1;
-      VARRAY_INT (set_in_loop, i) = 1;
-    }
-
-#ifdef AVOID_CCMODE_COPIES
-  /* Don't try to move insns which set CC registers if we should not
-     create CCmode register copies.  */
-  for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
-    if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
-      VARRAY_CHAR (may_not_optimize, i) = 1;
-#endif
-
-  bcopy ((char *) &set_in_loop->data,
-        (char *) &n_times_set->data, nregs * sizeof (int));
+  /* Allocate extra space for REGs that might be created by load_mems.
+     We allocate a little extra slop as well, in the hopes that we
+     won't have to reallocate the regs array.  */
+  loop_regs_scan (loop, loop_info->mems_idx + 16, &insn_count);
 
   if (loop_dump_stream)
     {
@@ -740,7 +649,7 @@ scan_loop (loop, flags)
     }
 
   /* Scan through the loop finding insns that are safe to move.
-     Set set_in_loop negative for the reg being set, so that
+     Set REGS->ARRAY[I].SET_IN_LOOP negative for the reg I being set, so that
      this reg will be considered invariant for subsequent insns.
      We consider whether subsequent insns use the reg
      in deciding whether it is worth actually moving.
@@ -759,7 +668,7 @@ scan_loop (loop, flags)
       if (GET_CODE (p) == INSN
          && (set = single_set (p))
          && GET_CODE (SET_DEST (set)) == REG
-         && ! VARRAY_CHAR (may_not_optimize, REGNO (SET_DEST (set))))
+         && ! regs->array[REGNO (SET_DEST (set))].may_not_optimize)
        {
          int tem1 = 0;
          int tem2 = 0;
@@ -823,12 +732,11 @@ scan_loop (loop, flags)
          else if ((tem = loop_invariant_p (loop, src))
                   && (dependencies == 0
                       || (tem2 = loop_invariant_p (loop, dependencies)) != 0)
-                  && (VARRAY_INT (set_in_loop,
-                                  REGNO (SET_DEST (set))) == 1
+                  && (regs->array[REGNO (SET_DEST (set))].set_in_loop == 1
                       || (tem1
                           = consec_sets_invariant_p
                           (loop, SET_DEST (set),
-                           VARRAY_INT (set_in_loop, REGNO (SET_DEST (set))),
+                           regs->array[REGNO (SET_DEST (set))].set_in_loop,
                            p)))
                   /* If the insn can cause a trap (such as divide by zero),
                      can't move it unless it's guaranteed to be executed
@@ -856,12 +764,12 @@ scan_loop (loop, flags)
                 SMALL_REGISTER_CLASSES and SET_SRC is a hard register.  */
 
              if (loop_info->has_call
-                 && VARRAY_RTX (reg_single_usage, regno) != 0
-                 && VARRAY_RTX (reg_single_usage, regno) != const0_rtx
+                 && regs->array[regno].single_usage != 0
+                 && regs->array[regno].single_usage != const0_rtx
                  && REGNO_FIRST_UID (regno) == INSN_UID (p)
                  && (REGNO_LAST_UID (regno)
-                     == INSN_UID (VARRAY_RTX (reg_single_usage, regno)))
-                 && VARRAY_INT (set_in_loop, regno) == 1
+                     == INSN_UID (regs->array[regno].single_usage))
+                 && regs->array[regno].set_in_loop == 1
                  && ! side_effects_p (SET_SRC (set))
                  && ! find_reg_note (p, REG_RETVAL, NULL_RTX)
                  && (! SMALL_REGISTER_CLASSES
@@ -871,37 +779,33 @@ scan_loop (loop, flags)
                     a call-clobbered register and the life of REGNO
                     might span a call.  */
                  && ! modified_between_p (SET_SRC (set), p,
-                                          VARRAY_RTX
-                                          (reg_single_usage, regno))
-                 && no_labels_between_p (p, VARRAY_RTX (reg_single_usage, regno))
+                                          regs->array[regno].single_usage)
+                 && no_labels_between_p (p, regs->array[regno].single_usage)
                  && validate_replace_rtx (SET_DEST (set), SET_SRC (set),
-                                          VARRAY_RTX
-                                          (reg_single_usage, regno)))
+                                          regs->array[regno].single_usage))
                {
                  /* Replace any usage in a REG_EQUAL note.  Must copy the
                     new source, so that we don't get rtx sharing between the
                     SET_SOURCE and REG_NOTES of insn p.  */
-                 REG_NOTES (VARRAY_RTX (reg_single_usage, regno))
-                   = replace_rtx (REG_NOTES (VARRAY_RTX
-                                             (reg_single_usage, regno)),
+                 REG_NOTES (regs->array[regno].single_usage)
+                   = replace_rtx (REG_NOTES (regs->array[regno].single_usage),
                                   SET_DEST (set), copy_rtx (SET_SRC (set)));
 
                  PUT_CODE (p, NOTE);
                  NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED;
                  NOTE_SOURCE_FILE (p) = 0;
-                 VARRAY_INT (set_in_loop, regno) = 0;
+                 regs->array[regno].set_in_loop = 0;
                  continue;
                }
 
-             m = (struct movable *) alloca (sizeof (struct movable));
+             m = (struct movable *) xmalloc (sizeof (struct movable));
              m->next = 0;
              m->insn = p;
              m->set_src = src;
              m->dependencies = dependencies;
              m->set_dest = SET_DEST (set);
              m->force = 0;
-             m->consec = VARRAY_INT (set_in_loop,
-                                     REGNO (SET_DEST (set))) - 1;
+             m->consec = regs->array[REGNO (SET_DEST (set))].set_in_loop - 1;
              m->done = 0;
              m->forces = 0;
              m->partial = 0;
@@ -914,22 +818,15 @@ scan_loop (loop, flags)
                 or consec_sets_invariant_p returned 2
                 (only conditionally invariant).  */
              m->cond = ((tem | tem1 | tem2) > 1);
-             m->global = (uid_luid[REGNO_LAST_UID (regno)]
-                          > INSN_LUID (loop_end)
-                          || uid_luid[REGNO_FIRST_UID (regno)] < INSN_LUID (loop_start));
+             m->global =  LOOP_REG_GLOBAL_P (loop, regno);
              m->match = 0;
-             m->lifetime = (uid_luid[REGNO_LAST_UID (regno)]
-                            - uid_luid[REGNO_FIRST_UID (regno)]);
-             m->savings = VARRAY_INT (n_times_set, regno);
+             m->lifetime = LOOP_REG_LIFETIME (loop, regno);
+             m->savings = regs->array[regno].n_times_set;
              if (find_reg_note (p, REG_RETVAL, NULL_RTX))
                m->savings += libcall_benefit (p);
-             VARRAY_INT (set_in_loop, regno) = move_insn ? -2 : -1;
+             regs->array[regno].set_in_loop = move_insn ? -2 : -1;
              /* Add M to the end of the chain MOVABLES.  */
-             if (movables == 0)
-               movables = m;
-             else
-               last_movable->next = m;
-             last_movable = m;
+             loop_movables_add (movables, m);
 
              if (m->consec > 0)
                {
@@ -982,10 +879,10 @@ scan_loop (loop, flags)
                   && !reg_mentioned_p (SET_DEST (set), SET_SRC (set1)))
            {
              register int regno = REGNO (SET_DEST (set));
-             if (VARRAY_INT (set_in_loop, regno) == 2)
+             if (regs->array[regno].set_in_loop == 2)
                {
                  register struct movable *m;
-                 m = (struct movable *) alloca (sizeof (struct movable));
+                 m = (struct movable *) xmalloc (sizeof (struct movable));
                  m->next = 0;
                  m->insn = p;
                  m->set_dest = SET_DEST (set);
@@ -1016,12 +913,9 @@ scan_loop (loop, flags)
                     INSN_LUID and hence must make a conservative
                     assumption.  */
                  m->global = (INSN_UID (p) >= max_uid_for_loop
-                              || (uid_luid[REGNO_LAST_UID (regno)]
-                                  > INSN_LUID (loop_end))
-                              || (uid_luid[REGNO_FIRST_UID (regno)]
-                                  < INSN_LUID (p))
+                              || LOOP_REG_GLOBAL_P (loop, regno)
                               || (labels_in_range_p
-                                  (p, uid_luid[REGNO_FIRST_UID (regno)])));
+                                  (p, REGNO_FIRST_LUID (regno))));
                  if (maybe_never && m->global)
                    m->savemode = GET_MODE (SET_SRC (set1));
                  else
@@ -1029,16 +923,11 @@ scan_loop (loop, flags)
                  m->regno = regno;
                  m->cond = 0;
                  m->match = 0;
-                 m->lifetime = (uid_luid[REGNO_LAST_UID (regno)]
-                                - uid_luid[REGNO_FIRST_UID (regno)]);
+                 m->lifetime = LOOP_REG_LIFETIME (loop, regno);
                  m->savings = 1;
-                 VARRAY_INT (set_in_loop, regno) = -1;
+                 regs->array[regno].set_in_loop = -1;
                  /* Add M to the end of the chain MOVABLES.  */
-                 if (movables == 0)
-                   movables = m;
-                 else
-                   last_movable->next = m;
-                 last_movable = m;
+                 loop_movables_add (movables, m);
                }
            }
        }
@@ -1093,26 +982,31 @@ scan_loop (loop, flags)
      through the `match' field, and add the priorities of them
      all together as the priority of the first.  */
 
-  combine_movables (movables, nregs);
+  combine_movables (movables, regs);
 
   /* Now consider each movable insn to decide whether it is worth moving.
-     Store 0 in set_in_loop for each reg that is moved.
+     Store 0 in regs->array[I].set_in_loop for each reg I that is moved.
 
      Generally this increases code size, so do not move moveables when
      optimizing for code size.  */
 
   if (! optimize_size)
-    move_movables (loop, movables, threshold, insn_count, nregs);
+    move_movables (loop, movables, threshold, insn_count);
 
   /* Now candidates that still are negative are those not moved.
-     Change set_in_loop to indicate that those are not actually invariant.  */
-  for (i = 0; i < nregs; i++)
-    if (VARRAY_INT (set_in_loop, i) < 0)
-      VARRAY_INT (set_in_loop, i) = VARRAY_INT (n_times_set, i);
+     Change regs->array[I].set_in_loop to indicate that those are not actually
+     invariant.  */
+  for (i = 0; i < regs->num; i++)
+    if (regs->array[i].set_in_loop < 0)
+      regs->array[i].set_in_loop = regs->array[i].n_times_set;
 
   /* Now that we've moved some things out of the loop, we might be able to
      hoist even more memory references.  */
-  load_mems_and_recount_loop_regs_set (loop, &insn_count);
+  load_mems (loop);
+
+  /* Recalculate regs->array if load_mems has created new registers.  */
+  if (max_reg_num () > regs->num)
+    loop_regs_scan (loop, 0, &insn_count);
 
   for (update_start = loop_start;
        PREV_INSN (update_start)
@@ -1130,7 +1024,6 @@ scan_loop (loop, flags)
        /* Ensure our label doesn't go away.  */
        LABEL_NUSES (update_end)++;
 
-      the_movables = movables;
       strength_reduce (loop, insn_count, flags);
 
       reg_scan_update (update_start, update_end, loop_max_reg);
@@ -1141,10 +1034,13 @@ scan_loop (loop, flags)
        delete_insn (update_end);
     }
 
-  VARRAY_FREE (reg_single_usage);
-  VARRAY_FREE (set_in_loop);
-  VARRAY_FREE (n_times_set);
-  VARRAY_FREE (may_not_optimize);
+
+  /* The movable information is required for strength reduction.  */
+  loop_movables_free (movables);
+
+  free (regs->array);
+  regs->array = 0;
+  regs->num = 0;
 }
 \f
 /* Add elements to *OUTPUT to record all the pseudo-regs
@@ -1340,11 +1236,11 @@ skip_consec_insns (insn, count)
 
 static void
 ignore_some_movables (movables)
-     struct movable *movables;
+     struct loop_movables *movables;
 {
   register struct movable *m, *m1;
 
-  for (m = movables; m; m = m->next)
+  for (m = movables->head; m; m = m->next)
     {
       /* Is this a movable for the value of a libcall?  */
       rtx note = find_reg_note (m->insn, REG_RETVAL, NULL_RTX);
@@ -1358,7 +1254,7 @@ ignore_some_movables (movables)
             explicitly check each insn in the libcall (since invariant
             libcalls aren't that common).  */
          for (insn = XEXP (note, 0); insn != m->insn; insn = NEXT_INSN (insn))
-           for (m1 = movables; m1 != m; m1 = m1->next)
+           for (m1 = movables->head; m1 != m; m1 = m1->next)
              if (m1->insn == insn)
                m1->done = 1;
        }
@@ -1372,10 +1268,10 @@ ignore_some_movables (movables)
 
 static void
 force_movables (movables)
-     struct movable *movables;
+     struct loop_movables *movables;
 {
   register struct movable *m, *m1;
-  for (m1 = movables; m1; m1 = m1->next)
+  for (m1 = movables->head; m1; m1 = m1->next)
     /* Omit this if moving just the (SET (REG) 0) of a zero-extend.  */
     if (!m1->partial && !m1->done)
       {
@@ -1410,32 +1306,33 @@ force_movables (movables)
    one register.  */
 
 static void
-combine_movables (movables, nregs)
-     struct movable *movables;
-     int nregs;
+combine_movables (movables, regs)
+     struct loop_movables *movables;
+     struct loop_regs *regs;
 {
   register struct movable *m;
-  char *matched_regs = (char *) xmalloc (nregs);
+  char *matched_regs = (char *) xmalloc (regs->num);
   enum machine_mode mode;
 
   /* Regs that are set more than once are not allowed to match
      or be matched.  I'm no longer sure why not.  */
   /* Perhaps testing m->consec_sets would be more appropriate here?  */
 
-  for (m = movables; m; m = m->next)
-    if (m->match == 0 && VARRAY_INT (n_times_set, m->regno) == 1
+  for (m = movables->head; m; m = m->next)
+    if (m->match == 0 && regs->array[m->regno].n_times_set == 1
        && !m->partial)
       {
        register struct movable *m1;
        int regno = m->regno;
 
-       bzero (matched_regs, nregs);
+       memset (matched_regs, 0, regs->num);
        matched_regs[regno] = 1;
 
        /* We want later insns to match the first one.  Don't make the first
           one match any later ones.  So start this loop at m->next.  */
        for (m1 = m->next; m1; m1 = m1->next)
-         if (m != m1 && m1->match == 0 && VARRAY_INT (n_times_set, m1->regno) == 1
+         if (m != m1 && m1->match == 0 
+             && regs->array[m1->regno].n_times_set == 1
              /* A reg used outside the loop mustn't be eliminated.  */
              && !m1->global
              /* A reg used for zero-extending mustn't be eliminated.  */
@@ -1459,7 +1356,7 @@ combine_movables (movables, nregs)
                   && ((GET_CODE (m1->set_src) == REG
                        && matched_regs[REGNO (m1->set_src)])
                       || rtx_equal_for_loop_p (m->set_src, m1->set_src,
-                                               movables))))
+                                               movables, regs))))
              && ((m->dependencies == m1->dependencies)
                  || rtx_equal_p (m->dependencies, m1->dependencies)))
            {
@@ -1482,13 +1379,13 @@ combine_movables (movables, nregs)
 
       /* Combine all the registers for extension from mode MODE.
         Don't combine any that are used outside this loop.  */
-      for (m = movables; m; m = m->next)
+      for (m = movables->head; m; m = m->next)
        if (m->partial && ! m->global
            && mode == GET_MODE (SET_SRC (PATTERN (NEXT_INSN (m->insn)))))
          {
            register struct movable *m1;
-           int first = uid_luid[REGNO_FIRST_UID (m->regno)];
-           int last = uid_luid[REGNO_LAST_UID (m->regno)];
+           int first = REGNO_FIRST_LUID (m->regno);
+           int last = REGNO_LAST_LUID (m->regno);
 
            if (m0 == 0)
              {
@@ -1504,10 +1401,10 @@ combine_movables (movables, nregs)
 
            /* We already have one: check for overlap with those
               already combined together.  */
-           for (m1 = movables; m1 != m; m1 = m1->next)
+           for (m1 = movables->head; m1 != m; m1 = m1->next)
              if (m1 == m0 || (m1->partial && m1->match == m0))
-               if (! (uid_luid[REGNO_FIRST_UID (m1->regno)] > last
-                      || uid_luid[REGNO_LAST_UID (m1->regno)] < first))
+               if (! (REGNO_FIRST_LUID (m1->regno) > last
+                      || REGNO_LAST_LUID (m1->regno) < first))
                  goto overlap;
 
            /* No overlap: we can combine this with the others.  */
@@ -1530,17 +1427,17 @@ combine_movables (movables, nregs)
 static int
 regs_match_p (x, y, movables)
      rtx x, y;
-     struct movable *movables;
+     struct loop_movables *movables;
 {
   unsigned int xn = REGNO (x);
   unsigned int yn = REGNO (y);
   struct movable *mx, *my;
 
-  for (mx = movables; mx; mx = mx->next)
+  for (mx = movables->head; mx; mx = mx->next)
     if (mx->regno == xn)
       break;
 
-  for (my = movables; my; my = my->next)
+  for (my = movables->head; my; my = my->next)
     if (my->regno == yn)
       break;
 
@@ -1557,9 +1454,10 @@ regs_match_p (x, y, movables)
    equivalent constant, consider them equal.  */
 
 static int
-rtx_equal_for_loop_p (x, y, movables)
+rtx_equal_for_loop_p (x, y, movables, regs)
      rtx x, y;
-     struct movable *movables;
+     struct loop_movables *movables;
+     struct loop_regs *regs;
 {
   register int i;
   register int j;
@@ -1576,18 +1474,18 @@ rtx_equal_for_loop_p (x, y, movables)
 
   /* If we have a register and a constant, they may sometimes be
      equal.  */
-  if (GET_CODE (x) == REG && VARRAY_INT (set_in_loop, REGNO (x)) == -2
+  if (GET_CODE (x) == REG && regs->array[REGNO (x)].set_in_loop == -2
       && CONSTANT_P (y))
     {
-      for (m = movables; m; m = m->next)
+      for (m = movables->head; m; m = m->next)
        if (m->move_insn && m->regno == REGNO (x)
            && rtx_equal_p (m->set_src, y))
          return 1;
     }
-  else if (GET_CODE (y) == REG && VARRAY_INT (set_in_loop, REGNO (y)) == -2
+  else if (GET_CODE (y) == REG && regs->array[REGNO (y)].set_in_loop == -2
           && CONSTANT_P (x))
     {
-      for (m = movables; m; m = m->next)
+      for (m = movables->head; m; m = m->next)
        if (m->move_insn && m->regno == REGNO (y)
            && rtx_equal_p (m->set_src, x))
          return 1;
@@ -1637,12 +1535,14 @@ rtx_equal_for_loop_p (x, y, movables)
 
          /* And the corresponding elements must match.  */
          for (j = 0; j < XVECLEN (x, i); j++)
-           if (rtx_equal_for_loop_p (XVECEXP (x, i, j), XVECEXP (y, i, j), movables) == 0)
+           if (rtx_equal_for_loop_p (XVECEXP (x, i, j), XVECEXP (y, i, j),
+                                     movables, regs) == 0)
              return 0;
          break;
 
        case 'e':
-         if (rtx_equal_for_loop_p (XEXP (x, i), XEXP (y, i), movables) == 0)
+         if (rtx_equal_for_loop_p (XEXP (x, i), XEXP (y, i), movables, regs)
+             == 0)
            return 0;
          break;
 
@@ -1669,7 +1569,8 @@ rtx_equal_for_loop_p (x, y, movables)
 }
 \f
 /* If X contains any LABEL_REF's, add REG_LABEL notes for them to all
-  insns in INSNS which use the reference.  */
+   insns in INSNS which use the reference.  LABEL_NUSES for CODE_LABEL
+   references is incremented once for each added note. */
 
 static void
 add_label_notes (x, insns)
@@ -1690,8 +1591,12 @@ add_label_notes (x, insns)
          mark_jump_label for additional information).  */
       for (insn = insns; insn; insn = NEXT_INSN (insn))
        if (reg_mentioned_p (XEXP (x, 0), insn))
-         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL, XEXP (x, 0),
-                                               REG_NOTES (insn));
+         {
+           REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL, XEXP (x, 0),
+                                                 REG_NOTES (insn));
+           if (LABEL_P (XEXP (x, 0)))
+             LABEL_NUSES (XEXP (x, 0))++;
+         }
     }
 
   fmt = GET_RTX_FORMAT (code);
@@ -1710,13 +1615,14 @@ add_label_notes (x, insns)
    other throughout.  */
 
 static void
-move_movables (loop, movables, threshold, insn_count, nregs)
+move_movables (loop, movables, threshold, insn_count)
      struct loop *loop;
-     struct movable *movables;
+     struct loop_movables *movables;
      int threshold;
      int insn_count;
-     int nregs;
 {
+  struct loop_regs *regs = LOOP_REGS (loop);
+  int nregs = regs->num;
   rtx new_start = 0;
   register struct movable *m;
   register rtx p;
@@ -1728,9 +1634,9 @@ move_movables (loop, movables, threshold, insn_count, nregs)
   rtx *reg_map = (rtx *) xcalloc (nregs, sizeof (rtx));
   char *already_moved = (char *) xcalloc (nregs, sizeof (char));
 
-  num_movables = 0;
+  movables->num = 0;
 
-  for (m = movables; m; m = m->next)
+  for (m = movables->head; m; m = m->next)
     {
       /* Describe this movable insn.  */
 
@@ -1759,7 +1665,7 @@ move_movables (loop, movables, threshold, insn_count, nregs)
        }
 
       /* Count movables.  Value used in heuristics in strength_reduce.  */
-      num_movables++;
+      movables->num++;
 
       /* Ignore the insn if it's already done (it matched something else).
         Otherwise, see if it is now safe to move.  */
@@ -1788,7 +1694,7 @@ move_movables (loop, movables, threshold, insn_count, nregs)
          if (loop_dump_stream)
            fprintf (loop_dump_stream, "savings %d ", savings);
 
-         if (moved_once[regno] && loop_dump_stream)
+         if (regs->array[regno].moved_once && loop_dump_stream)
            fprintf (loop_dump_stream, "halved since already moved ");
 
          /* An insn MUST be moved if we already moved something else
@@ -1807,9 +1713,9 @@ move_movables (loop, movables, threshold, insn_count, nregs)
          if (already_moved[regno]
              || flag_move_all_movables
              || (threshold * savings * m->lifetime) >=
-                (moved_once[regno] ? insn_count * 2 : insn_count)
+                (regs->array[regno].moved_once ? insn_count * 2 : insn_count)
              || (m->forces && m->forces->done
-                 && VARRAY_INT (n_times_set, m->forces->regno) == 1))
+                 && regs->array[m->forces->regno].n_times_set == 1))
            {
              int count;
              register struct movable *m1;
@@ -1828,7 +1734,7 @@ move_movables (loop, movables, threshold, insn_count, nregs)
                  for (m1 = m; m1->match; m1 = m1->match);
                  newpat = gen_move_insn (SET_DEST (PATTERN (m->insn)),
                                          SET_DEST (PATTERN (m1->insn)));
-                 i1 = emit_insn_before (newpat, loop_start);
+                 i1 = loop_insn_hoist (loop, newpat);
 
                  /* Mark the moved, invariant reg as being allowed to
                     share a hard reg with the other matching invariant.  */
@@ -1852,7 +1758,7 @@ move_movables (loop, movables, threshold, insn_count, nregs)
                 the move insn before the loop.  */
              else if (m->move_insn)
                {
-                 rtx i1, temp;
+                 rtx i1, temp, seq;
 
                  for (count = m->consec; count >= 0; count--)
                    {
@@ -1889,11 +1795,12 @@ move_movables (loop, movables, threshold, insn_count, nregs)
                  start_sequence ();
                  emit_move_insn (m->set_dest, m->set_src);
                  temp = get_insns ();
+                 seq = gen_sequence ();
                  end_sequence ();
 
                  add_label_notes (m->set_src, temp);
 
-                 i1 = emit_insns_before (temp, loop_start);
+                 i1 = loop_insn_hoist (loop, seq);
                  if (! find_reg_note (i1, REG_EQUAL, NULL_RTX))
                    REG_NOTES (i1)
                      = gen_rtx_EXPR_LIST (m->is_equiv ? REG_EQUIV : REG_EQUAL,
@@ -1979,13 +1886,13 @@ move_movables (loop, movables, threshold, insn_count, nregs)
                              if (GET_CODE (temp) == CALL_INSN
                                  && fn_address != 0
                                  && reg_referenced_p (fn_reg, body))
-                               emit_insn_after (gen_move_insn (fn_reg,
-                                                               fn_address),
-                                                fn_address_insn);
+                               loop_insn_emit_after (loop, 0, fn_address_insn,
+                                                     gen_move_insn
+                                                     (fn_reg, fn_address));
 
                              if (GET_CODE (temp) == CALL_INSN)
                                {
-                                 i1 = emit_call_insn_before (body, loop_start);
+                                 i1 = loop_call_insn_hoist (loop, body);
                                  /* Because the USAGE information potentially
                                     contains objects other than hard registers
                                     we need to copy it.  */
@@ -1994,7 +1901,7 @@ move_movables (loop, movables, threshold, insn_count, nregs)
                                      = copy_rtx (CALL_INSN_FUNCTION_USAGE (temp));
                                }
                              else
-                               i1 = emit_insn_before (body, loop_start);
+                               i1 = loop_insn_hoist (loop, body);
                              if (first == 0)
                                first = i1;
                              if (temp == fn_address_insn)
@@ -2027,11 +1934,11 @@ move_movables (loop, movables, threshold, insn_count, nregs)
                            emit_move_insn (reg, tem);
                          sequence = gen_sequence ();
                          end_sequence ();
-                         i1 = emit_insn_before (sequence, loop_start);
+                         i1 = loop_insn_hoist (loop, sequence);
                        }
                      else if (GET_CODE (p) == CALL_INSN)
                        {
-                         i1 = emit_call_insn_before (PATTERN (p), loop_start);
+                         i1 = loop_call_insn_hoist (loop, PATTERN (p));
                          /* Because the USAGE information potentially
                             contains objects other than hard registers
                             we need to copy it.  */
@@ -2041,16 +1948,18 @@ move_movables (loop, movables, threshold, insn_count, nregs)
                        }
                      else if (count == m->consec && m->move_insn_first)
                        {
+                         rtx seq;
                          /* The SET_SRC might not be invariant, so we must
                             use the REG_EQUAL note.  */
                          start_sequence ();
                          emit_move_insn (m->set_dest, m->set_src);
                          temp = get_insns ();
+                         seq = gen_sequence ();
                          end_sequence ();
 
                          add_label_notes (m->set_src, temp);
 
-                         i1 = emit_insns_before (temp, loop_start);
+                         i1 = loop_insn_hoist (loop, seq);
                          if (! find_reg_note (i1, REG_EQUAL, NULL_RTX))
                            REG_NOTES (i1)
                              = gen_rtx_EXPR_LIST ((m->is_equiv ? REG_EQUIV
@@ -2058,7 +1967,7 @@ move_movables (loop, movables, threshold, insn_count, nregs)
                                                   m->set_src, REG_NOTES (i1));
                        }
                      else
-                       i1 = emit_insn_before (PATTERN (p), loop_start);
+                       i1 = loop_insn_hoist (loop, PATTERN (p));
 
                      if (REG_NOTES (i1) == 0)
                        {
@@ -2115,11 +2024,11 @@ move_movables (loop, movables, threshold, insn_count, nregs)
              already_moved[regno] = 1;
 
              /* This reg has been moved out of one loop.  */
-             moved_once[regno] = 1;
+             regs->array[regno].moved_once = 1;
 
              /* The reg set here is now invariant.  */
              if (! m->partial)
-               VARRAY_INT (set_in_loop, regno) = 0;
+               regs->array[regno].set_in_loop = 0;
 
              m->done = 1;
 
@@ -2127,18 +2036,18 @@ move_movables (loop, movables, threshold, insn_count, nregs)
                 to say it lives at least the full length of this loop.
                 This will help guide optimizations in outer loops.  */
 
-             if (uid_luid[REGNO_FIRST_UID (regno)] > INSN_LUID (loop_start))
+             if (REGNO_FIRST_LUID (regno) > INSN_LUID (loop_start))
                /* This is the old insn before all the moved insns.
                   We can't use the moved insn because it is out of range
                   in uid_luid.  Only the old insns have luids.  */
                REGNO_FIRST_UID (regno) = INSN_UID (loop_start);
-             if (uid_luid[REGNO_LAST_UID (regno)] < INSN_LUID (loop_end))
+             if (REGNO_LAST_LUID (regno) < INSN_LUID (loop_end))
                REGNO_LAST_UID (regno) = INSN_UID (loop_end);
 
              /* Combine with this moved insn any other matching movables.  */
 
              if (! m->partial)
-               for (m1 = movables; m1; m1 = m1->next)
+               for (m1 = movables->head; m1; m1 = m1->next)
                  if (m1->match == m)
                    {
                      rtx temp;
@@ -2183,7 +2092,7 @@ move_movables (loop, movables, threshold, insn_count, nregs)
                      /* The reg merged here is now invariant,
                         if the reg it matches is invariant.  */
                      if (! m->partial)
-                       VARRAY_INT (set_in_loop, m1->regno) = 0;
+                       regs->array[m1->regno].set_in_loop = 0;
                    }
            }
          else if (loop_dump_stream)
@@ -2214,6 +2123,34 @@ move_movables (loop, movables, threshold, insn_count, nregs)
   free (reg_map);
   free (already_moved);
 }
+
+
+static void
+loop_movables_add (movables, m)
+     struct loop_movables *movables;
+     struct movable *m;
+{
+  if (movables->head == 0)
+    movables->head = m;
+  else
+    movables->last->next = m;
+  movables->last = m;
+}
+
+
+static void
+loop_movables_free (movables)
+     struct loop_movables *movables;
+{
+  struct movable *m;
+  struct movable *m_next;
+
+  for (m = movables->head; m; m = m_next)
+    {
+      m_next = m->next;
+      free (m);
+    }
+}  
 \f
 #if 0
 /* Scan X and replace the address of any MEM in it with ADDR.
@@ -2333,10 +2270,10 @@ count_nonfixed_reads (loop, x)
 }
 \f
 /* Scan a loop setting the elements `cont', `vtop', `loops_enclosed',
-   `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'.  */
+   `has_call', `has_nonconst_call', `has_volatile', `has_tablejump',
+   `unknown_address_altered', `unknown_constant_address_altered', and
+   `num_mem_sets' in LOOP.  Also, fill in the array `mems' and the
+   list `store_mems' in LOOP.  */
 
 static void
 prescan_loop (loop)
@@ -2354,18 +2291,31 @@ prescan_loop (loop)
   rtx exit_target = next_nonnote_insn (end);
 
   loop_info->has_indirect_jump = indirect_jump_in_function;
+  loop_info->pre_header_has_call = 0;
   loop_info->has_call = 0;
+  loop_info->has_nonconst_call = 0;
   loop_info->has_volatile = 0;
   loop_info->has_tablejump = 0;
   loop_info->has_multiple_exit_targets = 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;
-  num_mem_sets = 0;
+  loop_info->unknown_address_altered = 0;
+  loop_info->unknown_constant_address_altered = 0;
+  loop_info->store_mems = NULL_RTX;
+  loop_info->first_loop_store_insn = NULL_RTX;
+  loop_info->mems_idx = 0;
+  loop_info->num_mem_sets = 0;
+
+
+  for (insn = start; insn && GET_CODE (insn) != CODE_LABEL; 
+       insn = PREV_INSN (insn))
+    {
+      if (GET_CODE (insn) == CALL_INSN)
+       {
+         loop_info->pre_header_has_call = 1;
+         break;
+       }
+    }
 
   for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
        insn = NEXT_INSN (insn))
@@ -2386,7 +2336,10 @@ prescan_loop (loop)
       else if (GET_CODE (insn) == CALL_INSN)
        {
          if (! CONST_CALL_P (insn))
-           unknown_address_altered = 1;
+           {
+             loop_info->unknown_address_altered = 1;
+             loop_info->has_nonconst_call = 1;
+           }
          loop_info->has_call = 1;
        }
       else if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
@@ -2402,9 +2355,9 @@ prescan_loop (loop)
                  || GET_CODE (PATTERN (insn)) == ADDR_VEC))
            loop_info->has_tablejump = 1;
 
-         note_stores (PATTERN (insn), note_addr_stored, NULL);
-         if (! first_loop_store_insn && loop_store_mems)
-           first_loop_store_insn = insn;
+         note_stores (PATTERN (insn), note_addr_stored, loop_info);
+         if (! loop_info->first_loop_store_insn && loop_info->store_mems)
+           loop_info->first_loop_store_insn = insn;
 
          if (! loop_info->has_multiple_exit_targets
              && GET_CODE (insn) == JUMP_INSN
@@ -2453,7 +2406,7 @@ prescan_loop (loop)
   /* Now, rescan the loop, setting up the LOOP_MEMS array.  */
   if (/* An exception thrown by a called function might land us
         anywhere.  */
-      ! loop_info->has_call
+      ! loop_info->has_nonconst_call
       /* We don't want loads for MEMs moved to a location before the
         one at which their stack memory becomes allocated.  (Note
         that this is not a problem for malloc, etc., since those
@@ -2464,78 +2417,28 @@ prescan_loop (loop)
       && ! 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);
+      for_each_rtx (&insn, insert_loop_mem, loop_info);
 
   /* BLKmode MEMs are added to LOOP_STORE_MEM as necessary so
      that loop_invariant_p and load_mems can use true_dependence
      to determine what is really clobbered.  */
-  if (unknown_address_altered)
+  if (loop_info->unknown_address_altered)
     {
       rtx mem = gen_rtx_MEM (BLKmode, const0_rtx);
 
-      loop_store_mems = gen_rtx_EXPR_LIST (VOIDmode, mem, loop_store_mems);
+      loop_info->store_mems
+       = gen_rtx_EXPR_LIST (VOIDmode, mem, loop_info->store_mems);
     }
-  if (unknown_constant_address_altered)
+  if (loop_info->unknown_constant_address_altered)
     {
       rtx mem = gen_rtx_MEM (BLKmode, const0_rtx);
 
       RTX_UNCHANGING_P (mem) = 1;
-      loop_store_mems = gen_rtx_EXPR_LIST (VOIDmode, mem, loop_store_mems);
+      loop_info->store_mems
+       = gen_rtx_EXPR_LIST (VOIDmode, mem, loop_info->store_mems);
     }
 }
 \f
-/* LOOP->CONT_DOMINATOR is now the last label between the loop start
-   and the continue note that is a the destination of a (cond)jump after
-   the continue note.  If there is any (cond)jump between the loop start
-   and what we have so far as LOOP->CONT_DOMINATOR that has a
-   target between LOOP->CONT_DOMINATOR and the continue note, move
-   LOOP->CONT_DOMINATOR forward to that label; if a jump's
-   destination cannot be determined, clear LOOP->CONT_DOMINATOR.  */
-
-static void
-verify_dominator (loop)
-     struct loop *loop;
-{
-  rtx insn;
-
-  if (! loop->cont_dominator)
-    /* This can happen for an empty loop, e.g. in
-       gcc.c-torture/compile/920410-2.c  */
-    return;
-  if (loop->cont_dominator == const0_rtx)
-    {
-      loop->cont_dominator = 0;
-      return;
-    }
-  for (insn = loop->start; insn != loop->cont_dominator;
-       insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == JUMP_INSN
-         && GET_CODE (PATTERN (insn)) != RETURN)
-       {
-         rtx label = JUMP_LABEL (insn);
-         int label_luid;
-
-         /* If it is not a jump we can easily understand or for
-            which we do not have jump target information in the JUMP_LABEL
-            field (consider ADDR_VEC and ADDR_DIFF_VEC insns), then clear
-            LOOP->CONT_DOMINATOR.  */
-         if (! any_condjump_p (insn)
-             || label == NULL_RTX)
-           {
-             loop->cont_dominator = NULL_RTX;
-             return;
-           }
-
-         label_luid = INSN_LUID (label);
-         if (label_luid < INSN_LUID (loop->cont)
-             && (label_luid
-                 > INSN_LUID (loop->cont)))
-           loop->cont_dominator = label;
-       }
-    }
-}
-
 /* Scan the function looking for loops.  Record the start and end of each loop.
    Also mark as invalid loops any loops that contain a setjmp or are branched
    to from outside the loop.  */
@@ -2606,52 +2509,12 @@ find_and_verify_loops (f, loops)
              abort ();
 
            current_loop->end = insn;
-           verify_dominator (current_loop);
            current_loop = current_loop->outer;
            break;
 
          default:
            break;
          }
-      /* If for any loop, this is a jump insn between the NOTE_INSN_LOOP_CONT
-        and NOTE_INSN_LOOP_END notes, update loop->cont_dominator.  */
-      else if (GET_CODE (insn) == JUMP_INSN
-              && GET_CODE (PATTERN (insn)) != RETURN
-              && current_loop)
-       {
-         rtx label = JUMP_LABEL (insn);
-
-         if (! any_condjump_p (insn))
-           label = NULL_RTX;
-
-         loop = current_loop;
-         do
-           {
-             /* First see if we care about this loop.  */
-             if (loop->cont && loop->cont_dominator != const0_rtx)
-               {
-                 /* If the jump destination is not known, invalidate
-                    loop->cont_dominator.  */
-                 if (! label)
-                   loop->cont_dominator = const0_rtx;
-                 else
-                   /* Check if the destination is between loop start and
-                      cont.  */
-                   if ((INSN_LUID (label)
-                        < INSN_LUID (loop->cont))
-                       && (INSN_LUID (label)
-                           > INSN_LUID (loop->start))
-                       /* And if there is no later destination already
-                          recorded.  */
-                       && (! loop->cont_dominator
-                           || (INSN_LUID (label)
-                               > INSN_LUID (loop->cont_dominator))))
-                     loop->cont_dominator = label;
-               }
-             loop = loop->outer;
-           }
-         while (loop);
-       }
 
       /* Note that this will mark the NOTE_INSN_LOOP_END note as being in the
         enclosing loop, but this doesn't matter.  */
@@ -2864,9 +2727,9 @@ find_and_verify_loops (f, loops)
                           off LABEL_OUTSIDE_LOOP_P bit.  */
                        if (JUMP_LABEL (insn))
                          {
-                           for (q = 0,
-                                  r = this_loop->exit_labels;
-                                r; q = r, r = LABEL_NEXTREF (r))
+                           for (q = 0, r = this_loop->exit_labels;
+                                r;
+                                q = r, r = LABEL_NEXTREF (r))
                              if (XEXP (r, 0) == JUMP_LABEL (insn))
                                {
                                  LABEL_OUTSIDE_LOOP_P (r) = 0;
@@ -3094,32 +2957,34 @@ note_addr_stored (x, y, data)
      rtx y ATTRIBUTE_UNUSED;
      void *data ATTRIBUTE_UNUSED;
 {
+  struct loop_info *loop_info = data;
+
   if (x == 0 || GET_CODE (x) != MEM)
     return;
 
   /* Count number of memory writes.
      This affects heuristics in strength_reduce.  */
-  num_mem_sets++;
+  loop_info->num_mem_sets++;
 
   /* BLKmode MEM means all memory is clobbered.  */
-    if (GET_MODE (x) == BLKmode)
+  if (GET_MODE (x) == BLKmode)
     {
       if (RTX_UNCHANGING_P (x))
-       unknown_constant_address_altered = 1;
+       loop_info->unknown_constant_address_altered = 1;
       else
-       unknown_address_altered = 1;
+       loop_info->unknown_address_altered = 1;
 
       return;
     }
 
-  loop_store_mems = gen_rtx_EXPR_LIST (VOIDmode, x, loop_store_mems);
+  loop_info->store_mems = gen_rtx_EXPR_LIST (VOIDmode, x,
+                                            loop_info->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.  */
+   used more than once.  DATA is a pointer to a loop_regs structure.  */
 
 static void
 note_set_pseudo_multiple_uses (x, y, data)
@@ -3127,6 +2992,8 @@ note_set_pseudo_multiple_uses (x, y, data)
      rtx y ATTRIBUTE_UNUSED;
      void *data;
 {
+  struct loop_regs *regs = (struct loop_regs *) data;
+
   if (x == 0)
     return;
 
@@ -3142,9 +3009,9 @@ note_set_pseudo_multiple_uses (x, y, data)
   /* If we do not have usage information, or if we know the register
      is used more than once, note that fact for check_dbra_loop.  */
   if (REGNO (x) >= max_reg_before_loop
-      || ! VARRAY_RTX (reg_single_usage, REGNO (x))
-      || VARRAY_RTX (reg_single_usage, REGNO (x)) == const0_rtx)
-    *((int *) data) = 1;
+      || ! regs->array[REGNO (x)].single_usage
+      || regs->array[REGNO (x)].single_usage == const0_rtx)
+    regs->multiple_uses = 1;
 }
 \f
 /* Return nonzero if the rtx X is invariant over the current loop.
@@ -3152,13 +3019,15 @@ note_set_pseudo_multiple_uses (x, y, data)
    The value is 2 if we refer to something only conditionally invariant.
 
    A memory ref is invariant if it is not volatile and does not conflict
-   with anything stored in `loop_store_mems'.  */
+   with anything stored in `loop_info->store_mems'.  */
 
 int
 loop_invariant_p (loop, x)
      const struct loop *loop;
      register rtx x;
 {
+  struct loop_info *loop_info = LOOP_INFO (loop);
+  struct loop_regs *regs = LOOP_REGS (loop);
   register int i;
   register enum rtx_code code;
   register const char *fmt;
@@ -3209,10 +3078,10 @@ loop_invariant_p (loop, x)
          && REGNO (x) < FIRST_PSEUDO_REGISTER && call_used_regs[REGNO (x)])
        return 0;
 
-      if (VARRAY_INT (set_in_loop, REGNO (x)) < 0)
+      if (regs->array[REGNO (x)].set_in_loop < 0)
        return 2;
 
-      return VARRAY_INT (set_in_loop, REGNO (x)) == 0;
+      return regs->array[REGNO (x)].set_in_loop == 0;
 
     case MEM:
       /* Volatile memory references must be rejected.  Do this before
@@ -3222,7 +3091,7 @@ loop_invariant_p (loop, x)
        return 0;
 
       /* See if there is any dependence between a store and this load.  */
-      mem_list_entry = loop_store_mems;
+      mem_list_entry = loop_info->store_mems;
       while (mem_list_entry)
        {
          if (true_dependence (XEXP (mem_list_entry, 0), VOIDmode,
@@ -3291,12 +3160,13 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
      int n_sets;
      rtx reg, insn;
 {
+  struct loop_regs *regs = LOOP_REGS (loop);
   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;
-  int old = VARRAY_INT (set_in_loop, regno);
+  int old = regs->array[regno].set_in_loop;
   int value = 0;
   int this;
 
@@ -3304,7 +3174,7 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
   if (n_sets == 127)
     return 0;
 
-  VARRAY_INT (set_in_loop, regno) = 0;
+  regs->array[regno].set_in_loop = 0;
 
   while (count > 0)
     {
@@ -3343,12 +3213,12 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
        count--;
       else if (code != NOTE)
        {
-         VARRAY_INT (set_in_loop, regno) = old;
+         regs->array[regno].set_in_loop = old;
          return 0;
        }
     }
 
-  VARRAY_INT (set_in_loop, regno) = old;
+  regs->array[regno].set_in_loop = old;
   /* If loop_invariant_p ever returned 2, we return 2.  */
   return 1 + (value & 2);
 }
@@ -3391,19 +3261,19 @@ all_sets_invariant_p (reg, insn, table)
    a different insn, set USAGE[REGNO] to const0_rtx.  */
 
 static void
-find_single_use_in_loop (insn, x, usage)
+find_single_use_in_loop (regs, insn, x)
+     struct loop_regs *regs;
      rtx insn;
      rtx x;
-     varray_type usage;
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt = GET_RTX_FORMAT (code);
   int i, j;
 
   if (code == REG)
-    VARRAY_RTX (usage, REGNO (x))
-      = (VARRAY_RTX (usage, REGNO (x)) != 0
-        && VARRAY_RTX (usage, REGNO (x)) != insn)
+    regs->array[REGNO (x)].single_usage
+      = (regs->array[REGNO (x)].single_usage != 0
+        && regs->array[REGNO (x)].single_usage != insn)
        ? const0_rtx : insn;
 
   else if (code == SET)
@@ -3413,33 +3283,34 @@ find_single_use_in_loop (insn, x, usage)
         show up as a potential movable so we don't care how USAGE is set
         for it.  */
       if (GET_CODE (SET_DEST (x)) != REG)
-       find_single_use_in_loop (insn, SET_DEST (x), usage);
-      find_single_use_in_loop (insn, SET_SRC (x), usage);
+       find_single_use_in_loop (regs, insn, SET_DEST (x));
+      find_single_use_in_loop (regs, insn, SET_SRC (x));
     }
   else
     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
       {
        if (fmt[i] == 'e' && XEXP (x, i) != 0)
-         find_single_use_in_loop (insn, XEXP (x, i), usage);
+         find_single_use_in_loop (regs, insn, XEXP (x, i));
        else if (fmt[i] == 'E')
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           find_single_use_in_loop (insn, XVECEXP (x, i, j), usage);
+           find_single_use_in_loop (regs, insn, XVECEXP (x, i, j));
       }
 }
 \f
 /* Count and record any set in X which is contained in INSN.  Update
-   MAY_NOT_MOVE and LAST_SET for any register set in X.  */
+   REGS->array[I].MAY_NOT_OPTIMIZE and LAST_SET for any register I set
+   in X.  */
 
 static void
-count_one_set (insn, x, may_not_move, last_set)
+count_one_set (regs, insn, x, last_set)
+     struct loop_regs *regs;
      rtx insn, x;
-     varray_type may_not_move;
      rtx *last_set;
 {
   if (GET_CODE (x) == CLOBBER && GET_CODE (XEXP (x, 0)) == REG)
     /* Don't move a reg that has an explicit clobber.
        It's not worth the pain to try to do it correctly.  */
-    VARRAY_CHAR (may_not_move, REGNO (XEXP (x, 0))) = 1;
+    regs->array[REGNO (XEXP (x, 0))].may_not_optimize = 1;
 
   if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
     {
@@ -3456,84 +3327,21 @@ count_one_set (insn, x, may_not_move, last_set)
             in current basic block, and it was set before,
             it must be set in two basic blocks, so it cannot
             be moved out of the loop.  */
-         if (VARRAY_INT (set_in_loop, regno) > 0
-             && last_set[regno] == 0)
-           VARRAY_CHAR (may_not_move, regno) = 1;
+         if (regs->array[regno].set_in_loop > 0
+             && last_set == 0)
+           regs->array[regno].may_not_optimize = 1;
          /* If this is not first setting in current basic block,
             see if reg was used in between previous one and this.
             If so, neither one can be moved.  */
          if (last_set[regno] != 0
              && reg_used_between_p (dest, last_set[regno], insn))
-           VARRAY_CHAR (may_not_move, regno) = 1;
-         if (VARRAY_INT (set_in_loop, regno) < 127)
-           ++VARRAY_INT (set_in_loop, regno);
+           regs->array[regno].may_not_optimize = 1;
+         if (regs->array[regno].set_in_loop < 127)
+           ++regs->array[regno].set_in_loop;
          last_set[regno] = insn;
        }
     }
 }
-
-/* Increment SET_IN_LOOP at the index of each register
-   that is modified by an insn between FROM and TO.
-   If the value of an element of SET_IN_LOOP becomes 127 or more,
-   stop incrementing it, to avoid overflow.
-
-   Store in SINGLE_USAGE[I] the single insn in which register I is
-   used, if it is only used once.  Otherwise, it is set to 0 (for no
-   uses) or const0_rtx for more than one use.  This parameter may be zero,
-   in which case this processing is not done.
-
-   Store in *COUNT_PTR the number of actual instruction
-   in the loop.  We use this to decide what is worth moving out.  */
-
-/* last_set[n] is nonzero iff reg n has been set in the current basic block.
-   In that case, it is the insn that last set reg n.  */
-
-static void
-count_loop_regs_set (loop, may_not_move, single_usage, count_ptr, nregs)
-     const struct loop *loop;
-     varray_type may_not_move;
-     varray_type single_usage;
-     int *count_ptr;
-     int nregs;
-{
-  register rtx *last_set = (rtx *) xcalloc (nregs, sizeof (rtx));
-  register rtx insn;
-  register int count = 0;
-
-  for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
-       insn = NEXT_INSN (insn))
-    {
-      if (INSN_P (insn))
-       {
-         ++count;
-
-         /* Record registers that have exactly one use.  */
-         find_single_use_in_loop (insn, PATTERN (insn), single_usage);
-
-         /* Include uses in REG_EQUAL notes.  */
-         if (REG_NOTES (insn))
-           find_single_use_in_loop (insn, REG_NOTES (insn), single_usage);
-
-         if (GET_CODE (PATTERN (insn)) == SET
-             || GET_CODE (PATTERN (insn)) == CLOBBER)
-           count_one_set (insn, PATTERN (insn), may_not_move, last_set);
-         else if (GET_CODE (PATTERN (insn)) == PARALLEL)
-           {
-             register int i;
-             for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
-               count_one_set (insn, XVECEXP (PATTERN (insn), 0, i),
-                              may_not_move, last_set);
-           }
-       }
-
-      if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
-       bzero ((char *) last_set, nregs * sizeof (rtx));
-    }
-  *count_ptr = count;
-
-  /* Clean up.  */
-  free (last_set);
-}
 \f
 /* Given a loop that is bounded by LOOP->START and LOOP->END and that
    is entered at LOOP->SCAN_START, return 1 if the register set in SET
@@ -3574,34 +3382,6 @@ loop_reg_used_before_p (loop, set, insn)
 /* Bivs are recognized by `basic_induction_var';
    Givs by `general_induction_var'.  */
 
-/* Indexed by register number, indicates whether or not register is an
-   induction variable, and if so what type.  */
-
-varray_type reg_iv_type;
-
-/* Indexed by register number, contains pointer to `struct induction'
-   if register is an induction variable.  This holds general info for
-   all induction variables.  */
-
-varray_type reg_iv_info;
-
-/* Indexed by register number, contains pointer to `struct iv_class'
-   if register is a basic induction variable.  This holds info describing
-   the class (a related group) of induction variables that the biv belongs
-   to.  */
-
-struct iv_class **reg_biv_class;
-
-/* The head of a list which links together (via the next field)
-   every iv class for the current loop.  */
-
-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.  */
-unsigned int first_increment_giv, last_increment_giv;
-
 /* Communication with routines called via `note_stores'.  */
 
 static rtx note_insn;
@@ -3790,85 +3570,40 @@ for_each_insn_in_loop (loop, fncall)
     }
 }
 \f
-/* Perform strength reduction and induction variable elimination.
-
-   Pseudo registers created during this function will be beyond the last
-   valid index in several tables including n_times_set and regno_last_uid.
-   This does not cause a problem here, because the added registers cannot be
-   givs outside of their loop, and hence will never be reconsidered.
-   But scan_loop must check regnos to make sure they are in bounds.   */
-
 static void
-strength_reduce (loop, insn_count, flags)
+loop_bivs_find (loop)
      struct loop *loop;
-     int insn_count;
-     int flags;
 {
-  rtx p;
-  /* Temporary list pointers for traversing loop_iv_list.  */
+  struct loop_regs *regs = LOOP_REGS (loop);
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  /* Temporary list pointers for traversing ivs->list.  */
   struct iv_class *bl, **backbl;
-  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
-     and more registers are available.  */
-  /* ??? could set this to last value of threshold in move_movables */
-  int threshold = (loop_info->has_call ? 1 : 2) * (3 + n_non_fixed_regs);
-  /* Map of pseudo-register replacements.  */
-  rtx *reg_map = NULL;
-  int reg_map_size;
-  int call_seen;
-  rtx test;
-  rtx end_insert_before;
-  int n_extra_increment;
-  int unrolled_insn_copies = 0;
-  rtx loop_start = loop->start;
-  rtx loop_end = loop->end;
-  rtx loop_scan_start = loop->scan_start;
-
-  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 **)
-    xcalloc (max_reg_before_loop, sizeof (struct iv_class *));
-
-  loop_iv_list = 0;
-  addr_placeholder = gen_reg_rtx (Pmode);
-
-  /* Save insn immediately after the loop_end.  Insns inserted after loop_end
-     must be put before this insn, so that they will appear in the right
-     order (i.e. loop order).
 
-     If loop_end is the end of the current function, then emit a
-     NOTE_INSN_DELETED after loop_end and set end_insert_before to the
-     dummy note insn.  */
-  if (NEXT_INSN (loop_end) != 0)
-    end_insert_before = NEXT_INSN (loop_end);
-  else
-    end_insert_before = emit_note_after (NOTE_INSN_DELETED, loop_end);
+  ivs->list = 0;
 
   for_each_insn_in_loop (loop, check_insn_for_bivs);
-
-  /* Scan loop_iv_list to remove all regs that proved not to be bivs.
-     Make a sanity check against n_times_set.  */
-  for (backbl = &loop_iv_list, bl = *backbl; bl; bl = bl->next)
+  
+  /* Scan ivs->list to remove all regs that proved not to be bivs.
+     Make a sanity check against regs->n_times_set.  */
+  for (backbl = &ivs->list, bl = *backbl; bl; bl = bl->next)
     {
-      if (REG_IV_TYPE (bl->regno) != BASIC_INDUCT
+      if (REG_IV_TYPE (ivs, bl->regno) != BASIC_INDUCT
          /* Above happens if register modified by subreg, etc.  */
          /* Make sure it is not recognized as a basic induction var: */
-         || VARRAY_INT (n_times_set, bl->regno) != bl->biv_count
+         || regs->array[bl->regno].n_times_set != bl->biv_count
          /* If never incremented, it is invariant that we decided not to
             move.  So leave it alone.  */
          || ! bl->incremented)
        {
          if (loop_dump_stream)
-           fprintf (loop_dump_stream, "Reg %d: biv discarded, %s\n",
+           fprintf (loop_dump_stream, "Biv %d: discarded, %s\n",
                     bl->regno,
-                    (REG_IV_TYPE (bl->regno) != BASIC_INDUCT
+                    (REG_IV_TYPE (ivs, bl->regno) != BASIC_INDUCT
                      ? "not induction variable"
                      : (! bl->incremented ? "never incremented"
                         : "count error")));
 
-         REG_IV_TYPE (bl->regno) = NOT_BASIC_INDUCT;
+         REG_IV_TYPE (ivs, bl->regno) = NOT_BASIC_INDUCT;
          *backbl = bl->next;
        }
       else
@@ -3876,46 +3611,51 @@ strength_reduce (loop, insn_count, flags)
          backbl = &bl->next;
 
          if (loop_dump_stream)
-           fprintf (loop_dump_stream, "Reg %d: biv verified\n", bl->regno);
+           fprintf (loop_dump_stream, "Biv %d: verified\n", bl->regno);
        }
     }
+}
 
-  /* Exit if there are no bivs.  */
-  if (! loop_iv_list)
-    {
-      /* Can still unroll the loop anyways, but indicate that there is no
-        strength reduction info available.  */
-      if (flags & LOOP_UNROLL)
-       unroll_loop (loop, insn_count, end_insert_before, 0);
 
-      goto egress;
-    }
+/* Determine how BIVS are initialised by looking through pre-header
+   extended basic block.  */
+static void
+loop_bivs_init_find (loop)
+     struct loop *loop;
+{
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  /* Temporary list pointers for traversing ivs->list.  */
+  struct iv_class *bl;
+  int call_seen;
+  rtx p;
 
   /* Find initial value for each biv by searching backwards from loop_start,
      halting at first label.  Also record any test condition.  */
 
   call_seen = 0;
-  for (p = loop_start; p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
+  for (p = loop->start; p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
     {
+      rtx test;
+
       note_insn = p;
 
       if (GET_CODE (p) == CALL_INSN)
        call_seen = 1;
 
       if (INSN_P (p))
-       note_stores (PATTERN (p), record_initial, NULL);
+       note_stores (PATTERN (p), record_initial, ivs);
 
       /* Record any test of a biv that branches around the loop if no store
         between it and the start of loop.  We only care about tests with
         constants and registers and only certain of those.  */
       if (GET_CODE (p) == JUMP_INSN
          && JUMP_LABEL (p) != 0
-         && next_real_insn (JUMP_LABEL (p)) == next_real_insn (loop_end)
+         && next_real_insn (JUMP_LABEL (p)) == next_real_insn (loop->end)
          && (test = get_condition_for_loop (loop, p)) != 0
          && GET_CODE (XEXP (test, 0)) == REG
          && REGNO (XEXP (test, 0)) < max_reg_before_loop
-         && (bl = reg_biv_class[REGNO (XEXP (test, 0))]) != 0
-         && valid_initial_value_p (XEXP (test, 1), p, call_seen, loop_start)
+         && (bl = REG_IV_CLASS (ivs, REGNO (XEXP (test, 0)))) != 0
+         && valid_initial_value_p (XEXP (test, 1), p, call_seen, loop->start)
          && bl->init_insn == 0)
        {
          /* If an NE test, we have an initial value!  */
@@ -3929,11 +3669,22 @@ strength_reduce (loop, insn_count, flags)
            bl->initial_test = test;
        }
     }
+}
 
-  /* Look at the each biv and see if we can say anything better about its
-     initial value from any initializing insns set up above.  (This is done
-     in two passes to avoid missing SETs in a PARALLEL.)  */
-  for (backbl = &loop_iv_list; (bl = *backbl); backbl = &bl->next)
+
+/* Look at the each biv and see if we can say anything better about its
+   initial value from any initializing insns set up above.  (This is done
+   in two passes to avoid missing SETs in a PARALLEL.)  */
+static void
+loop_bivs_check (loop)
+     struct loop *loop;
+{
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  /* Temporary list pointers for traversing ivs->list.  */
+  struct iv_class *bl;
+  struct iv_class **backbl;
+
+  for (backbl = &ivs->list; (bl = *backbl); backbl = &bl->next)
     {
       rtx src;
       rtx note;
@@ -3953,408 +3704,567 @@ strength_reduce (loop, insn_count, flags)
 
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
-                "Biv %d initialized at insn %d: initial value ",
+                "Biv %d: initialized at insn %d: initial value ",
                 bl->regno, INSN_UID (bl->init_insn));
 
       if ((GET_MODE (src) == GET_MODE (regno_reg_rtx[bl->regno])
           || GET_MODE (src) == VOIDmode)
-         && valid_initial_value_p (src, bl->init_insn, call_seen, loop_start))
+         && valid_initial_value_p (src, bl->init_insn, 
+                                   LOOP_INFO (loop)->pre_header_has_call, 
+                                   loop->start))
        {
          bl->initial_value = src;
 
          if (loop_dump_stream)
            {
-             if (GET_CODE (src) == CONST_INT)
-               {
-                 fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (src));
-                 fputc ('\n', loop_dump_stream);
-               }
-             else
-               {
-                 print_rtl (loop_dump_stream, src);
-                 fprintf (loop_dump_stream, "\n");
-               }
+             print_simple_rtl (loop_dump_stream, src);
+             fputc ('\n', loop_dump_stream);
            }
        }
-      else
-       {
-         struct iv_class *bl2 = 0;
-         rtx increment = NULL_RTX;
-
-         /* Biv initial value is not a simple move.  If it is the sum of
-            another biv and a constant, check if both bivs are incremented
-            in lockstep.  Then we are actually looking at a giv.
-            For simplicity, we only handle the case where there is but a
-            single increment, and the register is not used elsewhere.  */
-         if (bl->biv_count == 1
-             && bl->regno < max_reg_before_loop
-             && uid_luid[REGNO_LAST_UID (bl->regno)] < INSN_LUID (loop_end)
-             && GET_CODE (src) == PLUS
-             && GET_CODE (XEXP (src, 0)) == REG
-             && CONSTANT_P (XEXP (src, 1))
-             && ((increment = biv_total_increment (bl)) != NULL_RTX))
-           {
-             unsigned int regno = REGNO (XEXP (src, 0));
+      /* If we can't make it a giv,
+        let biv keep initial value of "itself".  */
+      else if (loop_dump_stream)
+       fprintf (loop_dump_stream, "is complex\n");
+    }
+}
 
-             for (bl2 = loop_iv_list; bl2; bl2 = bl2->next)
-               if (bl2->regno == regno)
-                 break;
-           }
 
-         /* Now, can we transform this biv into a giv?  */
-         if (bl2
-             && bl2->biv_count == 1
-             && rtx_equal_p (increment, biv_total_increment (bl2))
-             /* init_insn is only set to insns that are before loop_start
-                without any intervening labels.  */
-             && ! reg_set_between_p (bl2->biv->src_reg,
-                                     PREV_INSN (bl->init_insn), loop_start)
-             /* The register from BL2 must be set before the register from
-                BL is set, or we must be able to move the latter set after
-                the former set.  Currently there can't be any labels
-                in-between when biv_total_increment returns nonzero both times
-                but we test it here in case some day some real cfg analysis
-                gets used to set always_computable.  */
-             && (loop_insn_first_p (bl2->biv->insn, bl->biv->insn)
-                 ? no_labels_between_p (bl2->biv->insn, bl->biv->insn)
-                 : (! reg_used_between_p (bl->biv->src_reg, bl->biv->insn,
-                                          bl2->biv->insn)
-                    && no_jumps_between_p (bl->biv->insn, bl2->biv->insn)))
-             && validate_change (bl->biv->insn,
-                                 &SET_SRC (single_set (bl->biv->insn)),
-                                 copy_rtx (src), 0))
-           {
-             rtx dominator = loop->cont_dominator;
-             rtx giv = bl->biv->src_reg;
-             rtx giv_insn = bl->biv->insn;
-             rtx after_giv = NEXT_INSN (giv_insn);
+/* Search the loop for general induction variables.  */
 
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream, "is giv of biv %d\n", bl2->regno);
-             /* Let this giv be discovered by the generic code.  */
-             REG_IV_TYPE (bl->regno) = UNKNOWN_INDUCT;
-             reg_biv_class[bl->regno] = (struct iv_class *) NULL_PTR;
-             /* We can get better optimization if we can move the giv setting
-                before the first giv use.  */
-             if (dominator
-                 && ! loop_insn_first_p (dominator, loop_scan_start)
-                 && ! reg_set_between_p (bl2->biv->src_reg, loop_start,
-                                         dominator)
-                 && ! reg_used_between_p (giv, loop_start, dominator)
-                 && ! reg_used_between_p (giv, giv_insn, loop_end))
-               {
-                 rtx p;
-                 rtx next;
+static void
+loop_givs_find (loop)
+     struct loop* loop;
+{
+  for_each_insn_in_loop (loop, check_insn_for_givs);
+}
 
-                 for (next = NEXT_INSN (dominator);; next = NEXT_INSN (next))
-                   {
-                     if (GET_CODE (next) == JUMP_INSN
-                         || (INSN_P (next)
-                             && insn_dependent_p (giv_insn, next)))
-                       break;
-#ifdef HAVE_cc0
-                     if (! INSN_P (next) || ! sets_cc0_p (PATTERN (next)))
+
+/* For each giv for which we still don't know whether or not it is
+   replaceable, check to see if it is replaceable because its final value
+   can be calculated.   */
+
+static void
+loop_givs_check (loop)
+     struct loop *loop;
+{
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  struct iv_class *bl;
+
+  for (bl = ivs->list; bl; bl = bl->next)
+    {
+      struct induction *v;
+
+      for (v = bl->giv; v; v = v->next_iv)
+       if (! v->replaceable && ! v->not_replaceable)
+         check_final_value (loop, v);
+    }
+}
+
+
+/* Return non-zero if it is possible to eliminate the biv BL provided
+   all givs are reduced.  This is possible if either the reg is not
+   used outside the loop, or we can compute what its final value will
+   be.  */
+
+static int
+loop_biv_eliminable_p (loop, bl, threshold, insn_count)
+     struct loop *loop;
+     struct iv_class *bl;
+     int threshold;
+     int insn_count;
+{
+  /* For architectures with a decrement_and_branch_until_zero insn,
+     don't do this if we put a REG_NONNEG note on the endtest for this
+     biv.  */
+
+#ifdef HAVE_decrement_and_branch_until_zero
+  if (bl->nonneg)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Cannot eliminate nonneg biv %d.\n", bl->regno);
+      return 0;
+    }
 #endif
-                       dominator = next;
-                   }
-                 if (loop_dump_stream)
-                   fprintf (loop_dump_stream, "move after insn %d\n",
-                            INSN_UID (dominator));
-                 /* Avoid problems with luids by actually moving the insn
-                    and adjusting all luids in the range.  */
-                 reorder_insns (giv_insn, giv_insn, dominator);
-                 for (p = dominator; INSN_UID (p) >= max_uid_for_loop;)
-                   p = PREV_INSN (p);
-                 compute_luids (giv_insn, after_giv, INSN_LUID (p));
-                 /* If the only purpose of the init insn is to initialize
-                    this giv, delete it.  */
-                 if (single_set (bl->init_insn)
-                     && ! reg_used_between_p (giv, bl->init_insn, loop_start))
-                   delete_insn (bl->init_insn);
-               }
-             else if (! loop_insn_first_p (bl2->biv->insn, bl->biv->insn))
+
+  /* Check that biv is used outside loop or if it has a final value.
+     Compare against bl->init_insn rather than loop->start.  We aren't
+     concerned with any uses of the biv between init_insn and
+     loop->start since these won't be affected by the value of the biv
+     elsewhere in the function, so long as init_insn doesn't use the
+     biv itself.  */
+  
+  if ((REGNO_LAST_LUID (bl->regno) < INSN_LUID (loop->end)
+       && bl->init_insn
+       && INSN_UID (bl->init_insn) < max_uid_for_loop
+       && REGNO_FIRST_LUID (bl->regno) >= INSN_LUID (bl->init_insn)
+       && ! reg_mentioned_p (bl->biv->dest_reg, SET_SRC (bl->init_set)))
+      || (bl->final_value = final_biv_value (loop, bl)))
+    return maybe_eliminate_biv (loop, bl, 0, threshold,        insn_count);
+  
+  if (loop_dump_stream)
+    {
+      fprintf (loop_dump_stream,
+              "Cannot eliminate biv %d.\n",
+              bl->regno);
+      fprintf (loop_dump_stream,
+              "First use: insn %d, last use: insn %d.\n",
+              REGNO_FIRST_UID (bl->regno),
+              REGNO_LAST_UID (bl->regno));
+    }
+  return 0;
+}
+
+
+/* Reduce each giv of BL that we have decided to reduce.  */
+
+static void
+loop_givs_reduce (loop, bl)
+     struct loop *loop;
+     struct iv_class *bl;
+{
+  struct induction *v;
+
+  for (v = bl->giv; v; v = v->next_iv)
+    {
+      struct induction *tv;
+      if (! v->ignore && v->same == 0)
+       {
+         int auto_inc_opt = 0;
+         
+         /* If the code for derived givs immediately below has already
+            allocated a new_reg, we must keep it.  */
+         if (! v->new_reg)
+           v->new_reg = gen_reg_rtx (v->mode);
+         
+#ifdef AUTO_INC_DEC
+         /* If the target has auto-increment addressing modes, and
+            this is an address giv, then try to put the increment
+            immediately after its use, so that flow can create an
+            auto-increment addressing mode.  */
+         if (v->giv_type == DEST_ADDR && bl->biv_count == 1
+             && bl->biv->always_executed && ! bl->biv->maybe_multiple
+             /* We don't handle reversed biv's because bl->biv->insn
+                does not have a valid INSN_LUID.  */
+             && ! bl->reversed
+             && v->always_executed && ! v->maybe_multiple
+             && INSN_UID (v->insn) < max_uid_for_loop)
+           {
+             /* If other giv's have been combined with this one, then
+                this will work only if all uses of the other giv's occur
+                before this giv's insn.  This is difficult to check.
+                
+                We simplify this by looking for the common case where
+                there is one DEST_REG giv, and this giv's insn is the
+                last use of the dest_reg of that DEST_REG giv.  If the
+                increment occurs after the address giv, then we can
+                perform the optimization.  (Otherwise, the increment
+                would have to go before other_giv, and we would not be
+                able to combine it with the address giv to get an
+                auto-inc address.)  */
+             if (v->combined_with)
                {
-                 rtx p = PREV_INSN (giv_insn);
-                 while (INSN_UID (p) >= max_uid_for_loop)
-                   p = PREV_INSN (p);
-                 reorder_insns (giv_insn, giv_insn, bl2->biv->insn);
-                 compute_luids (after_giv, NEXT_INSN (giv_insn),
-                                INSN_LUID (p));
+                 struct induction *other_giv = 0;
+                 
+                 for (tv = bl->giv; tv; tv = tv->next_iv)
+                   if (tv->same == v)
+                     {
+                       if (other_giv)
+                         break;
+                       else
+                         other_giv = tv;
+                     }
+                 if (! tv && other_giv
+                     && REGNO (other_giv->dest_reg) < max_reg_before_loop
+                     && (REGNO_LAST_UID (REGNO (other_giv->dest_reg))
+                         == INSN_UID (v->insn))
+                     && INSN_LUID (v->insn) < INSN_LUID (bl->biv->insn))
+                   auto_inc_opt = 1;
                }
-             /* Remove this biv from the chain.  */
-             *backbl = bl->next;
+             /* Check for case where increment is before the address
+                giv.  Do this test in "loop order".  */
+             else if ((INSN_LUID (v->insn) > INSN_LUID (bl->biv->insn)
+                       && (INSN_LUID (v->insn) < INSN_LUID (loop->scan_start)
+                           || (INSN_LUID (bl->biv->insn)
+                               > INSN_LUID (loop->scan_start))))
+                      || (INSN_LUID (v->insn) < INSN_LUID (loop->scan_start)
+                          && (INSN_LUID (loop->scan_start)
+                              < INSN_LUID (bl->biv->insn))))
+               auto_inc_opt = -1;
+             else
+               auto_inc_opt = 1;
+             
+#ifdef HAVE_cc0
+             {
+               rtx prev;
+               
+               /* We can't put an insn immediately after one setting
+                  cc0, or immediately before one using cc0.  */
+               if ((auto_inc_opt == 1 && sets_cc0_p (PATTERN (v->insn)))
+                   || (auto_inc_opt == -1
+                       && (prev = prev_nonnote_insn (v->insn)) != 0
+                       && INSN_P (prev)
+                       && sets_cc0_p (PATTERN (prev))))
+                 auto_inc_opt = 0;
+             }
+#endif
+             
+             if (auto_inc_opt)
+               v->auto_inc_opt = 1;
            }
-
-         /* If we can't make it a giv,
-            let biv keep initial value of "itself".  */
-         else if (loop_dump_stream)
-           fprintf (loop_dump_stream, "is complex\n");
+#endif
+         
+         /* For each place where the biv is incremented, add an insn
+            to increment the new, reduced reg for the giv.  */
+         for (tv = bl->biv; tv; tv = tv->next_iv)
+           {
+             rtx insert_before;
+             
+             if (! auto_inc_opt)
+               insert_before = tv->insn;
+             else if (auto_inc_opt == 1)
+               insert_before = NEXT_INSN (v->insn);
+             else
+               insert_before = v->insn;
+             
+             if (tv->mult_val == const1_rtx)
+               loop_iv_add_mult_emit_before (loop, tv->add_val, v->mult_val,
+                                             v->new_reg, v->new_reg, 
+                                             0, insert_before);
+             else /* tv->mult_val == const0_rtx */
+               /* A multiply is acceptable here
+                  since this is presumed to be seldom executed.  */
+               loop_iv_add_mult_emit_before (loop, tv->add_val, v->mult_val,
+                                             v->add_val, v->new_reg, 
+                                             0, insert_before);
+           }
+         
+         /* Add code at loop start to initialize giv's reduced reg.  */
+         
+         loop_iv_add_mult_hoist (loop,
+                                 extend_value_for_giv (v, bl->initial_value),
+                                 v->mult_val, v->add_val, v->new_reg);
        }
     }
+}
+
 
-  /* If a biv is unconditionally incremented several times in a row, convert
-     all but the last increment into a giv.  */
+/* Check for givs whose first use is their definition and whose
+   last use is the definition of another giv.  If so, it is likely
+   dead and should not be used to derive another giv nor to
+   eliminate a biv.  */
 
-  /* Get an upper bound for the number of registers
-     we might have after all bivs have been processed.  */
-  first_increment_giv = max_reg_num ();
-  for (n_extra_increment = 0, bl = loop_iv_list; bl; bl = bl->next)
-    n_extra_increment += bl->biv_count - 1;
+static void
+loop_givs_dead_check (loop, bl)
+     struct loop *loop ATTRIBUTE_UNUSED;
+     struct iv_class *bl;
+{
+  struct induction *v;
 
-  /* If the loop contains volatile memory references do not allow any
-     replacements to take place, since this could loose the volatile
-     markers.  */
-  if (n_extra_increment  && ! loop_info->has_volatile)
+  for (v = bl->giv; v; v = v->next_iv)
     {
-      unsigned int nregs = first_increment_giv + n_extra_increment;
+      if (v->ignore
+         || (v->same && v->same->ignore))
+       continue;
+      
+      if (v->giv_type == DEST_REG
+         && REGNO_FIRST_UID (REGNO (v->dest_reg)) == INSN_UID (v->insn))
+       {
+         struct induction *v1;
+         
+         for (v1 = bl->giv; v1; v1 = v1->next_iv)
+           if (REGNO_LAST_UID (REGNO (v->dest_reg)) == INSN_UID (v1->insn))
+             v->maybe_dead = 1;
+       }
+    }
+}
 
-      /* Reallocate reg_iv_type and reg_iv_info.  */
-      VARRAY_GROW (reg_iv_type, nregs);
-      VARRAY_GROW (reg_iv_info, nregs);
 
-      for (bl = loop_iv_list; bl; bl = bl->next)
+static void
+loop_givs_rescan (loop, bl, reg_map)
+     struct loop *loop;
+     struct iv_class *bl;
+     rtx *reg_map;
+{
+  struct induction *v;
+
+  for (v = bl->giv; v; v = v->next_iv)
+    {
+      if (v->same && v->same->ignore)
+       v->ignore = 1;
+      
+      if (v->ignore)
+       continue;
+      
+      /* Update expression if this was combined, in case other giv was
+        replaced.  */
+      if (v->same)
+       v->new_reg = replace_rtx (v->new_reg,
+                                 v->same->dest_reg, v->same->new_reg);
+      
+      /* See if this register is known to be a pointer to something.  If
+        so, see if we can find the alignment.  First see if there is a
+        destination register that is a pointer.  If so, this shares the
+        alignment too.  Next see if we can deduce anything from the
+        computational information.  If not, and this is a DEST_ADDR
+        giv, at least we know that it's a pointer, though we don't know
+        the alignment.  */
+      if (GET_CODE (v->new_reg) == REG
+         && v->giv_type == DEST_REG
+         && REG_POINTER (v->dest_reg))
+       mark_reg_pointer (v->new_reg,
+                         REGNO_POINTER_ALIGN (REGNO (v->dest_reg)));
+      else if (GET_CODE (v->new_reg) == REG
+              && REG_POINTER (v->src_reg))
+       {
+         unsigned int align = REGNO_POINTER_ALIGN (REGNO (v->src_reg));
+         
+         if (align == 0
+             || GET_CODE (v->add_val) != CONST_INT
+             || INTVAL (v->add_val) % (align / BITS_PER_UNIT) != 0)
+           align = 0;
+         
+         mark_reg_pointer (v->new_reg, align);
+       }
+      else if (GET_CODE (v->new_reg) == REG
+              && GET_CODE (v->add_val) == REG
+              && REG_POINTER (v->add_val))
+       {
+         unsigned int align = REGNO_POINTER_ALIGN (REGNO (v->add_val));
+         
+         if (align == 0 || GET_CODE (v->mult_val) != CONST_INT
+             || INTVAL (v->mult_val) % (align / BITS_PER_UNIT) != 0)
+           align = 0;
+         
+         mark_reg_pointer (v->new_reg, align);
+       }
+      else if (GET_CODE (v->new_reg) == REG && v->giv_type == DEST_ADDR)
+       mark_reg_pointer (v->new_reg, 0);
+      
+      if (v->giv_type == DEST_ADDR)
+       /* Store reduced reg as the address in the memref where we found
+          this giv.  */
+       validate_change (v->insn, v->location, v->new_reg, 0);
+      else if (v->replaceable)
+       {
+         reg_map[REGNO (v->dest_reg)] = v->new_reg;
+       }
+      else
+       {
+         /* Not replaceable; emit an insn to set the original giv reg from
+            the reduced giv, same as above.  */
+         loop_insn_emit_after (loop, 0, v->insn, 
+                               gen_move_insn (v->dest_reg, v->new_reg));
+       }
+      
+      /* When a loop is reversed, givs which depend on the reversed
+        biv, and which are live outside the loop, must be set to their
+        correct final value.  This insn is only needed if the giv is
+        not replaceable.  The correct final value is the same as the
+        value that the giv starts the reversed loop with.  */
+      if (bl->reversed && ! v->replaceable)
+       loop_iv_add_mult_sink (loop, 
+                              extend_value_for_giv (v, bl->initial_value),
+                              v->mult_val, v->add_val, v->dest_reg);
+      else if (v->final_value)
+       loop_insn_sink_or_swim (loop, 
+                               gen_move_insn (v->dest_reg, v->final_value));
+      
+      if (loop_dump_stream)
        {
-         struct induction **vp, *v, *next;
-         int biv_dead_after_loop = 0;
+         fprintf (loop_dump_stream, "giv at %d reduced to ",
+                  INSN_UID (v->insn));
+         print_simple_rtl (loop_dump_stream, v->new_reg);
+         fprintf (loop_dump_stream, "\n");
+       }
+    }
+}
 
-         /* The biv increments lists are in reverse order.  Fix this
-             first.  */
-         for (v = bl->biv, bl->biv = 0; v; v = next)
-           {
-             next = v->next_iv;
-             v->next_iv = bl->biv;
-             bl->biv = v;
-           }
 
-         /* We must guard against the case that an early exit between v->insn
-            and next->insn leaves the biv live after the loop, since that
-            would mean that we'd be missing an increment for the final
-            value.  The following test to set biv_dead_after_loop is like
-            the first part of the test to set bl->eliminable.
-            We don't check here if we can calculate the final value, since
-            this can't succeed if we already know that there is a jump
-            between v->insn and next->insn, yet next->always_executed is
-            set and next->maybe_multiple is cleared.  Such a combination
-            implies that the jump destination is outside the loop.
-            If we want to make this check more sophisticated, we should
-            check each branch between v->insn and next->insn individually
-            to see if the biv is dead at its destination.  */
-
-         if (uid_luid[REGNO_LAST_UID (bl->regno)] < INSN_LUID (loop_end)
-             && bl->init_insn
-             && INSN_UID (bl->init_insn) < max_uid_for_loop
-             && (uid_luid[REGNO_FIRST_UID (bl->regno)]
-                 >= INSN_LUID (bl->init_insn))
-#ifdef HAVE_decrement_and_branch_until_zero
-             && ! bl->nonneg
+static int
+loop_giv_reduce_benefit (loop, bl, v, test_reg)
+     struct loop *loop ATTRIBUTE_UNUSED;
+     struct iv_class *bl;
+     struct induction *v;
+     rtx test_reg;
+{
+  int add_cost;
+  int benefit;
+
+  benefit = v->benefit;
+  PUT_MODE (test_reg, v->mode);
+  add_cost = iv_add_mult_cost (bl->biv->add_val, v->mult_val,
+                              test_reg, test_reg);
+  
+  /* Reduce benefit if not replaceable, since we will insert a
+     move-insn to replace the insn that calculates this giv.  Don't do
+     this unless the giv is a user variable, since it will often be
+     marked non-replaceable because of the duplication of the exit
+     code outside the loop.  In such a case, the copies we insert are
+     dead and will be deleted.  So they don't have a cost.  Similar
+     situations exist.  */
+  /* ??? The new final_[bg]iv_value code does a much better job of
+     finding replaceable giv's, and hence this code may no longer be
+     necessary.  */
+  if (! v->replaceable && ! bl->eliminable
+      && REG_USERVAR_P (v->dest_reg))
+    benefit -= copy_cost;
+  
+  /* Decrease the benefit to count the add-insns that we will insert
+     to increment the reduced reg for the giv.  ??? This can
+     overestimate the run-time cost of the additional insns, e.g. if
+     there are multiple basic blocks that increment the biv, but only
+     one of these blocks is executed during each iteration.  There is
+     no good way to detect cases like this with the current structure
+     of the loop optimizer.  This code is more accurate for
+     determining code size than run-time benefits.  */
+  benefit -= add_cost * bl->biv_count;
+
+  /* Decide whether to strength-reduce this giv or to leave the code
+     unchanged (recompute it from the biv each time it is used).  This
+     decision can be made independently for each giv.  */
+
+#ifdef AUTO_INC_DEC
+  /* Attempt to guess whether autoincrement will handle some of the
+     new add insns; if so, increase BENEFIT (undo the subtraction of
+     add_cost that was done above).  */
+  if (v->giv_type == DEST_ADDR
+      /* Increasing the benefit is risky, since this is only a guess.
+        Avoid increasing register pressure in cases where there would
+        be no other benefit from reducing this giv.  */
+      && benefit > 0
+      && GET_CODE (v->mult_val) == CONST_INT)
+    {
+      int size = GET_MODE_SIZE (GET_MODE (v->mem));
+
+      if (HAVE_POST_INCREMENT
+         && INTVAL (v->mult_val) == size)
+       benefit += add_cost * bl->biv_count;
+      else if (HAVE_PRE_INCREMENT
+              && INTVAL (v->mult_val) == size)
+       benefit += add_cost * bl->biv_count;
+      else if (HAVE_POST_DECREMENT
+              && -INTVAL (v->mult_val) == size)
+       benefit += add_cost * bl->biv_count;
+      else if (HAVE_PRE_DECREMENT
+              && -INTVAL (v->mult_val) == size)
+       benefit += add_cost * bl->biv_count;
+    }
 #endif
-             && ! reg_mentioned_p (bl->biv->dest_reg, SET_SRC (bl->init_set)))
-           biv_dead_after_loop = 1;
 
-         for (vp = &bl->biv, next = *vp; v = next, next = v->next_iv;)
-           {
-             HOST_WIDE_INT offset;
-             rtx set, add_val, old_reg, dest_reg, last_use_insn, note;
-             int old_regno, new_regno;
-             rtx next_loc_insn;
-
-             if (! v->always_executed
-                 || v->maybe_multiple
-                 || GET_CODE (v->add_val) != CONST_INT
-                 || ! next->always_executed
-                 || next->maybe_multiple
-                 || ! CONSTANT_P (next->add_val)
-                 || v->mult_val != const1_rtx
-                 || next->mult_val != const1_rtx
-                 || ! (biv_dead_after_loop
-                       || no_jumps_between_p (v->insn, next->insn)))
-               {
-                 vp = &v->next_iv;
-                 continue;
-               }
-             offset = INTVAL (v->add_val);
-             set = single_set (v->insn);
-             add_val = plus_constant (next->add_val, offset);
-             old_reg = v->dest_reg;
-             dest_reg = gen_reg_rtx (v->mode);
-
-             /* Unlike reg_iv_type / reg_iv_info, the other three arrays
-                have been allocated with some slop space, so we may not
-                actually need to reallocate them.  If we do, the following
-                if statement will be executed just once in this loop.  */
-             if ((unsigned) max_reg_num () > n_times_set->num_elements)
-               {
-                 /* Grow all the remaining arrays.  */
-                 VARRAY_GROW (set_in_loop, nregs);
-                 VARRAY_GROW (n_times_set, nregs);
-                 VARRAY_GROW (may_not_optimize, nregs);
-                 VARRAY_GROW (reg_single_usage, nregs);
-               }
+  return benefit;
+}
 
-             /* Some bivs are incremented with a multi-insn sequence.
-                The first insn contains the add.  */
-             next_loc_insn = next->insn;
-             while (NOTE_P (next_loc_insn)
-                    || ! loc_mentioned_in_p (next->location,
-                                             PATTERN (next_loc_insn)))
-               next_loc_insn = PREV_INSN (next_loc_insn);
 
-             if (next_loc_insn == v->insn)
-               abort ();
+/* Free IV structures for LOOP.  */
 
-             if (! validate_change (next_loc_insn, next->location, add_val, 0))
-               {
-                 vp = &v->next_iv;
-                 continue;
-               }
+static void
+loop_ivs_free (loop)
+     struct loop *loop;
+{
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  struct iv_class *iv = ivs->list;
+  
+  free (ivs->regs);
 
-             /* Here we can try to eliminate the increment by combining
-                it into the uses.  */
+  while (iv)
+    {
+      struct iv_class *next = iv->next;
+      struct induction *induction;
+      struct induction *next_induction;
+      
+      for (induction = iv->biv; induction; induction = next_induction)
+       {
+         next_induction = induction->next_iv;
+         free (induction);
+       }
+      for (induction = iv->giv; induction; induction = next_induction)
+       {
+         next_induction = induction->next_iv;
+         free (induction);
+       }
+      
+      free (iv);
+      iv = next;
+    }
+}
 
-             /* Set last_use_insn so that we can check against it.  */
 
-             for (last_use_insn = v->insn, p = NEXT_INSN (v->insn);
-                  p != next_loc_insn;
-                  p = next_insn_in_loop (loop, p))
-               {
-                 if (!INSN_P (p))
-                   continue;
-                 if (reg_mentioned_p (old_reg, PATTERN (p)))
-                   {
-                     last_use_insn = p;
-                   }
-               }
+/* Perform strength reduction and induction variable elimination.
 
-             /* If we can't get the LUIDs for the insns, we can't
-                calculate the lifetime.  This is likely from unrolling
-                of an inner loop, so there is little point in making this
-                a DEST_REG giv anyways.  */
-             if (INSN_UID (v->insn) >= max_uid_for_loop
-                 || INSN_UID (last_use_insn) >= max_uid_for_loop
-                 || ! validate_change (v->insn, &SET_DEST (set), dest_reg, 0))
-               {
-                 /* Change the increment at NEXT back to what it was.  */
-                 if (! validate_change (next_loc_insn, next->location,
-                     next->add_val, 0))
-                   abort ();
-                 vp = &v->next_iv;
-                 continue;
-               }
-             next->add_val = add_val;
-             v->dest_reg = dest_reg;
-             v->giv_type = DEST_REG;
-             v->location = &SET_SRC (set);
-             v->cant_derive = 0;
-             v->combined_with = 0;
-             v->maybe_dead = 0;
-             v->derive_adjustment = 0;
-             v->same = 0;
-             v->ignore = 0;
-             v->new_reg = 0;
-             v->final_value = 0;
-             v->same_insn = 0;
-             v->auto_inc_opt = 0;
-             v->unrolled = 0;
-             v->shared = 0;
-             v->derived_from = 0;
-             v->always_computable = 1;
-             v->always_executed = 1;
-             v->replaceable = 1;
-             v->no_const_addval = 0;
-
-             old_regno = REGNO (old_reg);
-             new_regno = REGNO (dest_reg);
-             VARRAY_INT (set_in_loop, old_regno)--;
-             VARRAY_INT (set_in_loop, new_regno) = 1;
-             VARRAY_INT (n_times_set, old_regno)--;
-             VARRAY_INT (n_times_set, new_regno) = 1;
-             VARRAY_CHAR (may_not_optimize, new_regno) = 0;
-
-             REG_IV_TYPE (new_regno) = GENERAL_INDUCT;
-             REG_IV_INFO (new_regno) = v;
-
-             /* If next_insn has a REG_EQUAL note that mentiones OLD_REG,
-                it must be replaced.  */
-             note = find_reg_note (next->insn, REG_EQUAL, NULL_RTX);
-             if (note && reg_mentioned_p (old_reg, XEXP (note, 0)))
-               XEXP (note, 0) = copy_rtx (SET_SRC (single_set (next->insn)));
-
-             /* Remove the increment from the list of biv increments,
-                and record it as a giv.  */
-             *vp = next;
-             bl->biv_count--;
-             v->next_iv = bl->giv;
-             bl->giv = v;
-             bl->giv_count++;
-             v->benefit = rtx_cost (SET_SRC (set), SET);
-             bl->total_benefit += v->benefit;
-
-             /* Now replace the biv with DEST_REG in all insns between
-                the replaced increment and the next increment, and
-                remember the last insn that needed a replacement.  */
-             for (last_use_insn = v->insn, p = NEXT_INSN (v->insn);
-                  p != next_loc_insn;
-                  p = next_insn_in_loop (loop, p))
-               {
-                 rtx note;
+   Pseudo registers created during this function will be beyond the
+   last valid index in several tables including
+   REGS->ARRAY[I].N_TIMES_SET and REGNO_LAST_UID.  This does not cause a
+   problem here, because the added registers cannot be givs outside of
+   their loop, and hence will never be reconsidered.  But scan_loop
+   must check regnos to make sure they are in bounds.  */
 
-                 if (! INSN_P (p))
-                   continue;
-                 if (reg_mentioned_p (old_reg, PATTERN (p)))
-                   {
-                     last_use_insn = p;
-                     if (! validate_replace_rtx (old_reg, dest_reg, p))
-                       abort ();
-                   }
-                 for (note = REG_NOTES (p); note; note = XEXP (note, 1))
-                   {
-                     if (GET_CODE (note) == EXPR_LIST)
-                       XEXP (note, 0)
-                         = replace_rtx (XEXP (note, 0), old_reg, dest_reg);
-                   }
-               }
+static void
+strength_reduce (loop, insn_count, flags)
+     struct loop *loop;
+     int insn_count;
+     int flags;
+{
+  struct loop_info *loop_info = LOOP_INFO (loop);
+  struct loop_regs *regs = LOOP_REGS (loop);
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  rtx p;
+  /* Temporary list pointer for traversing ivs->list.  */
+  struct iv_class *bl;
+  /* Ratio of extra register life span we can justify
+     for saving an instruction.  More if loop doesn't call subroutines
+     since in that case saving an insn makes more difference
+     and more registers are available.  */
+  /* ??? could set this to last value of threshold in move_movables */
+  int threshold = (loop_info->has_call ? 1 : 2) * (3 + n_non_fixed_regs);
+  /* Map of pseudo-register replacements.  */
+  rtx *reg_map = NULL;
+  int reg_map_size;
+  int unrolled_insn_copies = 0;
+  rtx test_reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
 
-             v->last_use = last_use_insn;
-             v->lifetime = INSN_LUID (last_use_insn) - INSN_LUID (v->insn);
-             /* If the lifetime is zero, it means that this register is really
-                a dead store.  So mark this as a giv that can be ignored.
-                This will not prevent the biv from being eliminated.  */
-             if (v->lifetime == 0)
-               v->ignore = 1;
+  addr_placeholder = gen_reg_rtx (Pmode);
 
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream,
-                        "Increment %d of biv %d converted to giv %d.\n\n",
-                        INSN_UID (v->insn), old_regno, new_regno);
-           }
-       }
+  ivs->n_regs = max_reg_before_loop;
+  ivs->regs = (struct iv *) xcalloc (ivs->n_regs, sizeof (struct iv));
+
+  /* Find all BIVs in loop.  */
+  loop_bivs_find (loop);
+
+  /* Exit if there are no bivs.  */
+  if (! ivs->list)
+    {
+      /* Can still unroll the loop anyways, but indicate that there is no
+        strength reduction info available.  */
+      if (flags & LOOP_UNROLL)
+       unroll_loop (loop, insn_count, 0);
+
+      loop_ivs_free (loop);
+      return;
     }
-  last_increment_giv = max_reg_num () - 1;
 
-  /* Search the loop for general induction variables.  */
+  /* Determine how BIVS are initialised by looking through pre-header
+     extended basic block.  */
+  loop_bivs_init_find (loop);
 
-  for_each_insn_in_loop (loop, check_insn_for_givs);
+  /* Look at the each biv and see if we can say anything better about its
+     initial value from any initializing insns set up above.  */
+  loop_bivs_check (loop);
+
+  /* Search the loop for general induction variables.  */
+  loop_givs_find (loop);
 
   /* Try to calculate and save the number of loop iterations.  This is
      set to zero if the actual number can not be calculated.  This must
      be called after all giv's have been identified, since otherwise it may
      fail if the iteration variable is a giv.  */
-
   loop_iterations (loop);
 
   /* Now for each giv for which we still don't know whether or not it is
      replaceable, check to see if it is replaceable because its final value
      can be calculated.  This must be done after loop_iterations is called,
      so that final_giv_value will work correctly.  */
-
-  for (bl = loop_iv_list; bl; bl = bl->next)
-    {
-      struct induction *v;
-
-      for (v = bl->giv; v; v = v->next_iv)
-       if (! v->replaceable && ! v->not_replaceable)
-         check_final_value (loop, v);
-    }
+  loop_givs_check (loop);
 
   /* Try to prove that the loop counter variable (if any) is always
      nonnegative; if so, record that fact with a REG_NONNEG note
@@ -4363,76 +4273,34 @@ strength_reduce (loop, insn_count, flags)
 
   /* Create reg_map to hold substitutions for replaceable giv regs.
      Some givs might have been made from biv increments, so look at
-     reg_iv_type for a suitable size.  */
-  reg_map_size = reg_iv_type->num_elements;
+     ivs->reg_iv_type for a suitable size.  */
+  reg_map_size = ivs->n_regs;
   reg_map = (rtx *) xcalloc (reg_map_size, sizeof (rtx));
 
   /* Examine each iv class for feasibility of strength reduction/induction
      variable elimination.  */
 
-  for (bl = loop_iv_list; bl; bl = bl->next)
+  for (bl = ivs->list; bl; bl = bl->next)
     {
       struct induction *v;
       int benefit;
-      int all_reduced;
-      rtx final_value = 0;
-      unsigned int nregs;
-
+      
       /* Test whether it will be possible to eliminate this biv
-        provided all givs are reduced.  This is possible if either
-        the reg is not used outside the loop, or we can compute
-        what its final value will be.
-
-        For architectures with a decrement_and_branch_until_zero insn,
-        don't do this if we put a REG_NONNEG note on the endtest for
-        this biv.  */
-
-      /* Compare against bl->init_insn rather than loop_start.
-        We aren't concerned with any uses of the biv between
-        init_insn and loop_start since these won't be affected
-        by the value of the biv elsewhere in the function, so
-        long as init_insn doesn't use the biv itself.
-        March 14, 1989 -- self@bayes.arc.nasa.gov */
-
-      if ((uid_luid[REGNO_LAST_UID (bl->regno)] < INSN_LUID (loop_end)
-          && bl->init_insn
-          && INSN_UID (bl->init_insn) < max_uid_for_loop
-          && uid_luid[REGNO_FIRST_UID (bl->regno)] >= INSN_LUID (bl->init_insn)
-#ifdef HAVE_decrement_and_branch_until_zero
-          && ! bl->nonneg
-#endif
-          && ! reg_mentioned_p (bl->biv->dest_reg, SET_SRC (bl->init_set)))
-         || ((final_value = final_biv_value (loop, bl))
-#ifdef HAVE_decrement_and_branch_until_zero
-             && ! bl->nonneg
-#endif
-             ))
-       bl->eliminable = maybe_eliminate_biv (loop, bl, 0, threshold,
-                                             insn_count);
-      else
-       {
-         if (loop_dump_stream)
-           {
-             fprintf (loop_dump_stream,
-                      "Cannot eliminate biv %d.\n",
-                      bl->regno);
-             fprintf (loop_dump_stream,
-                      "First use: insn %d, last use: insn %d.\n",
-                      REGNO_FIRST_UID (bl->regno),
-                      REGNO_LAST_UID (bl->regno));
-           }
-       }
+        provided all givs are reduced.  */
+      bl->eliminable = loop_biv_eliminable_p (loop, bl, threshold, insn_count);
+
+      /* Check each extension dependent giv in this class to see if its
+        root biv is safe from wrapping in the interior mode.  */
+      check_ext_dependant_givs (bl, loop_info);
 
       /* Combine all giv's for this iv_class.  */
-      combine_givs (bl);
+      combine_givs (regs, bl);
 
       /* This will be true at the end, if all givs which depend on this
         biv have been strength reduced.
         We can't (currently) eliminate the biv unless this is so.  */
-      all_reduced = 1;
+      bl->all_reduced = 1;
 
-      /* Check each giv in this class to see if we will benefit by reducing
-        it.  Skip giv's combined with others.  */
       for (v = bl->giv; v; v = v->next_iv)
        {
          struct induction *tv;
@@ -4440,54 +4308,10 @@ strength_reduce (loop, insn_count, flags)
          if (v->ignore || v->same)
            continue;
 
-         benefit = v->benefit;
-
-         /* Reduce benefit if not replaceable, since we will insert
-            a move-insn to replace the insn that calculates this giv.
-            Don't do this unless the giv is a user variable, since it
-            will often be marked non-replaceable because of the duplication
-            of the exit code outside the loop.  In such a case, the copies
-            we insert are dead and will be deleted.  So they don't have
-            a cost.  Similar situations exist.  */
-         /* ??? The new final_[bg]iv_value code does a much better job
-            of finding replaceable giv's, and hence this code may no longer
-            be necessary.  */
-         if (! v->replaceable && ! bl->eliminable
-             && REG_USERVAR_P (v->dest_reg))
-           benefit -= copy_cost;
-
-         /* Decrease the benefit to count the add-insns that we will
-            insert to increment the reduced reg for the giv.  */
-         benefit -= add_cost * bl->biv_count;
-
-         /* Decide whether to strength-reduce this giv or to leave the code
-            unchanged (recompute it from the biv each time it is used).
-            This decision can be made independently for each giv.  */
-
-#ifdef AUTO_INC_DEC
-         /* Attempt to guess whether autoincrement will handle some of the
-            new add insns; if so, increase BENEFIT (undo the subtraction of
-            add_cost that was done above).  */
-         if (v->giv_type == DEST_ADDR
-             && GET_CODE (v->mult_val) == CONST_INT)
-           {
-             if (HAVE_POST_INCREMENT
-                 && INTVAL (v->mult_val) == GET_MODE_SIZE (v->mem_mode))
-               benefit += add_cost * bl->biv_count;
-             else if (HAVE_PRE_INCREMENT
-                      && INTVAL (v->mult_val) == GET_MODE_SIZE (v->mem_mode))
-               benefit += add_cost * bl->biv_count;
-             else if (HAVE_POST_DECREMENT
-                      && -INTVAL (v->mult_val) == GET_MODE_SIZE (v->mem_mode))
-               benefit += add_cost * bl->biv_count;
-             else if (HAVE_PRE_DECREMENT
-                      && -INTVAL (v->mult_val) == GET_MODE_SIZE (v->mem_mode))
-               benefit += add_cost * bl->biv_count;
-           }
-#endif
+         benefit = loop_giv_reduce_benefit (loop, bl, v, test_reg);
 
          /* If an insn is not to be strength reduced, then set its ignore
-            flag, and clear all_reduced.  */
+            flag, and clear bl->all_reduced.  */
 
          /* A giv that depends on a reversed biv must be reduced if it is
             used after the loop exit, otherwise, it would have the wrong
@@ -4495,8 +4319,9 @@ strength_reduce (loop, insn_count, flags)
             of such giv's whether or not we know they are used after the loop
             exit.  */
 
-         if ( ! flag_reduce_all_givs && v->lifetime * threshold * benefit < insn_count
-             && ! bl->reversed )
+         if (! flag_reduce_all_givs
+             && v->lifetime * threshold * benefit < insn_count
+             && ! bl->reversed)
            {
              if (loop_dump_stream)
                fprintf (loop_dump_stream,
@@ -4504,7 +4329,7 @@ strength_reduce (loop, insn_count, flags)
                         INSN_UID (v->insn),
                         v->lifetime * threshold * benefit, insn_count);
              v->ignore = 1;
-             all_reduced = 0;
+             bl->all_reduced = 0;
            }
          else
            {
@@ -4520,7 +4345,7 @@ strength_reduce (loop, insn_count, flags)
                               "giv of insn %d: would need a multiply.\n",
                               INSN_UID (v->insn));
                    v->ignore = 1;
-                   all_reduced = 0;
+                   bl->all_reduced = 0;
                    break;
                  }
            }
@@ -4530,337 +4355,44 @@ strength_reduce (loop, insn_count, flags)
         last use is the definition of another giv.  If so, it is likely
         dead and should not be used to derive another giv nor to
         eliminate a biv.  */
-      for (v = bl->giv; v; v = v->next_iv)
-       {
-         if (v->ignore
-             || (v->same && v->same->ignore))
-           continue;
-
-         if (v->last_use)
-           {
-             struct induction *v1;
+      loop_givs_dead_check (loop, bl);
 
-             for (v1 = bl->giv; v1; v1 = v1->next_iv)
-               if (v->last_use == v1->insn)
-                 v->maybe_dead = 1;
-           }
-         else if (v->giv_type == DEST_REG
-             && REGNO_FIRST_UID (REGNO (v->dest_reg)) == INSN_UID (v->insn))
-           {
-             struct induction *v1;
+      /* Reduce each giv that we decided to reduce.  */
+      loop_givs_reduce (loop, bl);
 
-             for (v1 = bl->giv; v1; v1 = v1->next_iv)
-               if (REGNO_LAST_UID (REGNO (v->dest_reg)) == INSN_UID (v1->insn))
-                 v->maybe_dead = 1;
-           }
-       }
+      /* Rescan all givs.  If a giv is the same as a giv not reduced, mark it
+        as not reduced.
 
-      /* Now that we know which givs will be reduced, try to rearrange the
-         combinations to reduce register pressure.
-         recombine_givs calls find_life_end, which needs reg_iv_type and
-        reg_iv_info to be valid for all pseudos.  We do the necessary
-        reallocation here since it allows to check if there are still
-        more bivs to process.  */
-      nregs = max_reg_num ();
-      if (nregs > reg_iv_type->num_elements)
-       {
-         /* If there are still more bivs to process, allocate some slack
-            space so that we're not constantly reallocating these arrays.  */
-         if (bl->next)
-           nregs += nregs / 4;
-         /* Reallocate reg_iv_type and reg_iv_info.  */
-         VARRAY_GROW (reg_iv_type, nregs);
-         VARRAY_GROW (reg_iv_info, nregs);
-       }
-      recombine_givs (loop, bl, flags & LOOP_UNROLL);
+        For each giv register that can be reduced now: if replaceable,
+        substitute reduced reg wherever the old giv occurs;
+        else add new move insn "giv_reg = reduced_reg".  */
+      loop_givs_rescan (loop, bl, reg_map);
 
-      /* Reduce each giv that we decided to reduce.  */
-
-      for (v = bl->giv; v; v = v->next_iv)
-       {
-         struct induction *tv;
-         if (! v->ignore && v->same == 0)
-           {
-             int auto_inc_opt = 0;
-
-             /* If the code for derived givs immediately below has already
-                allocated a new_reg, we must keep it.  */
-             if (! v->new_reg)
-               v->new_reg = gen_reg_rtx (v->mode);
-
-             if (v->derived_from)
-               {
-                 struct induction *d = v->derived_from;
-
-                 /* In case d->dest_reg is not replaceable, we have
-                    to replace it in v->insn now.  */
-                 if (! d->new_reg)
-                   d->new_reg = gen_reg_rtx (d->mode);
-                 PATTERN (v->insn)
-                   = replace_rtx (PATTERN (v->insn), d->dest_reg, d->new_reg);
-                 PATTERN (v->insn)
-                   = replace_rtx (PATTERN (v->insn), v->dest_reg, v->new_reg);
-                 /* For each place where the biv is incremented, add an
-                    insn to set the new, reduced reg for the giv.
-                    We used to do this only for biv_count != 1, but
-                    this fails when there is a giv after a single biv
-                    increment, e.g. when the last giv was expressed as
-                    pre-decrement.  */
-                 for (tv = bl->biv; tv; tv = tv->next_iv)
-                   {
-                     /* We always emit reduced giv increments before the
-                        biv increment when bl->biv_count != 1.  So by
-                        emitting the add insns for derived givs after the
-                        biv increment, they pick up the updated value of
-                        the reduced giv.
-                        If the reduced giv is processed with
-                        auto_inc_opt == 1, then it is incremented earlier
-                        than the biv, hence we'll still pick up the right
-                        value.
-                        If it's processed with auto_inc_opt == -1,
-                        that implies that the biv increment is before the
-                        first reduced giv's use.  The derived giv's lifetime
-                        is after the reduced giv's lifetime, hence in this
-                        case, the biv increment doesn't matter.  */
-                     emit_insn_after (copy_rtx (PATTERN (v->insn)), tv->insn);
-                   }
-                 continue;
-               }
-
-#ifdef AUTO_INC_DEC
-             /* If the target has auto-increment addressing modes, and
-                this is an address giv, then try to put the increment
-                immediately after its use, so that flow can create an
-                auto-increment addressing mode.  */
-             if (v->giv_type == DEST_ADDR && bl->biv_count == 1
-                 && bl->biv->always_executed && ! bl->biv->maybe_multiple
-                 /* We don't handle reversed biv's because bl->biv->insn
-                    does not have a valid INSN_LUID.  */
-                 && ! bl->reversed
-                 && v->always_executed && ! v->maybe_multiple
-                 && INSN_UID (v->insn) < max_uid_for_loop)
-               {
-                 /* If other giv's have been combined with this one, then
-                    this will work only if all uses of the other giv's occur
-                    before this giv's insn.  This is difficult to check.
-
-                    We simplify this by looking for the common case where
-                    there is one DEST_REG giv, and this giv's insn is the
-                    last use of the dest_reg of that DEST_REG giv.  If the
-                    increment occurs after the address giv, then we can
-                    perform the optimization.  (Otherwise, the increment
-                    would have to go before other_giv, and we would not be
-                    able to combine it with the address giv to get an
-                    auto-inc address.)  */
-                 if (v->combined_with)
-                   {
-                     struct induction *other_giv = 0;
-
-                     for (tv = bl->giv; tv; tv = tv->next_iv)
-                       if (tv->same == v)
-                         {
-                           if (other_giv)
-                             break;
-                           else
-                             other_giv = tv;
-                         }
-                     if (! tv && other_giv
-                         && REGNO (other_giv->dest_reg) < max_reg_before_loop
-                         && (REGNO_LAST_UID (REGNO (other_giv->dest_reg))
-                             == INSN_UID (v->insn))
-                         && INSN_LUID (v->insn) < INSN_LUID (bl->biv->insn))
-                       auto_inc_opt = 1;
-                   }
-                 /* Check for case where increment is before the address
-                    giv.  Do this test in "loop order".  */
-                 else if ((INSN_LUID (v->insn) > INSN_LUID (bl->biv->insn)
-                           && (INSN_LUID (v->insn) < INSN_LUID (loop_scan_start)
-                               || (INSN_LUID (bl->biv->insn)
-                                   > INSN_LUID (loop_scan_start))))
-                          || (INSN_LUID (v->insn) < INSN_LUID (loop_scan_start)
-                              && (INSN_LUID (loop_scan_start)
-                                  < INSN_LUID (bl->biv->insn))))
-                   auto_inc_opt = -1;
-                 else
-                   auto_inc_opt = 1;
-
-#ifdef HAVE_cc0
-                 {
-                   rtx prev;
-
-                   /* We can't put an insn immediately after one setting
-                      cc0, or immediately before one using cc0.  */
-                   if ((auto_inc_opt == 1 && sets_cc0_p (PATTERN (v->insn)))
-                       || (auto_inc_opt == -1
-                           && (prev = prev_nonnote_insn (v->insn)) != 0
-                           && INSN_P (prev)
-                           && sets_cc0_p (PATTERN (prev))))
-                     auto_inc_opt = 0;
-                 }
-#endif
-
-                 if (auto_inc_opt)
-                   v->auto_inc_opt = 1;
-               }
-#endif
-
-             /* For each place where the biv is incremented, add an insn
-                to increment the new, reduced reg for the giv.  */
-             for (tv = bl->biv; tv; tv = tv->next_iv)
-               {
-                 rtx insert_before;
-
-                 if (! auto_inc_opt)
-                   insert_before = tv->insn;
-                 else if (auto_inc_opt == 1)
-                   insert_before = NEXT_INSN (v->insn);
-                 else
-                   insert_before = v->insn;
-
-                 if (tv->mult_val == const1_rtx)
-                   emit_iv_add_mult (tv->add_val, v->mult_val,
-                                     v->new_reg, v->new_reg, insert_before);
-                 else /* tv->mult_val == const0_rtx */
-                   /* A multiply is acceptable here
-                      since this is presumed to be seldom executed.  */
-                   emit_iv_add_mult (tv->add_val, v->mult_val,
-                                     v->add_val, v->new_reg, insert_before);
-               }
-
-             /* Add code at loop start to initialize giv's reduced reg.  */
-
-             emit_iv_add_mult (bl->initial_value, v->mult_val,
-                               v->add_val, v->new_reg, loop_start);
-           }
-       }
-
-      /* Rescan all givs.  If a giv is the same as a giv not reduced, mark it
-        as not reduced.
-
-        For each giv register that can be reduced now: if replaceable,
-        substitute reduced reg wherever the old giv occurs;
-        else add new move insn "giv_reg = reduced_reg".  */
-
-      for (v = bl->giv; v; v = v->next_iv)
-       {
-         if (v->same && v->same->ignore)
-           v->ignore = 1;
-
-         if (v->ignore)
-           continue;
-
-         /* Update expression if this was combined, in case other giv was
-            replaced.  */
-         if (v->same)
-           v->new_reg = replace_rtx (v->new_reg,
-                                     v->same->dest_reg, v->same->new_reg);
-
-         if (v->giv_type == DEST_ADDR)
-           /* Store reduced reg as the address in the memref where we found
-              this giv.  */
-           validate_change (v->insn, v->location, v->new_reg, 0);
-         else if (v->replaceable)
-           {
-             reg_map[REGNO (v->dest_reg)] = v->new_reg;
-
-#if 0
-             /* I can no longer duplicate the original problem.  Perhaps
-                this is unnecessary now?  */
-
-             /* Replaceable; it isn't strictly necessary to delete the old
-                insn and emit a new one, because v->dest_reg is now dead.
-
-                However, especially when unrolling loops, the special
-                handling for (set REG0 REG1) in the second cse pass may
-                make v->dest_reg live again.  To avoid this problem, emit
-                an insn to set the original giv reg from the reduced giv.
-                We can not delete the original insn, since it may be part
-                of a LIBCALL, and the code in flow that eliminates dead
-                libcalls will fail if it is deleted.  */
-             emit_insn_after (gen_move_insn (v->dest_reg, v->new_reg),
-                              v->insn);
-#endif
-           }
-         else
-           {
-             /* Not replaceable; emit an insn to set the original giv reg from
-                the reduced giv, same as above.  */
-             emit_insn_after (gen_move_insn (v->dest_reg, v->new_reg),
-                              v->insn);
-           }
-
-         /* When a loop is reversed, givs which depend on the reversed
-            biv, and which are live outside the loop, must be set to their
-            correct final value.  This insn is only needed if the giv is
-            not replaceable.  The correct final value is the same as the
-            value that the giv starts the reversed loop with.  */
-         if (bl->reversed && ! v->replaceable)
-           emit_iv_add_mult (bl->initial_value, v->mult_val,
-                             v->add_val, v->dest_reg, end_insert_before);
-         else if (v->final_value)
-           {
-             rtx insert_before;
-
-             /* If the loop has multiple exits, emit the insn before the
-                loop to ensure that it will always be executed no matter
-                how the loop exits.  Otherwise, emit the insn after the loop,
-                since this is slightly more efficient.  */
-             if (loop->exit_count)
-               insert_before = loop_start;
-             else
-               insert_before = end_insert_before;
-             emit_insn_before (gen_move_insn (v->dest_reg, v->final_value),
-                               insert_before);
-
-#if 0
-             /* If the insn to set the final value of the giv was emitted
-                before the loop, then we must delete the insn inside the loop
-                that sets it.  If this is a LIBCALL, then we must delete
-                every insn in the libcall.  Note, however, that
-                final_giv_value will only succeed when there are multiple
-                exits if the giv is dead at each exit, hence it does not
-                matter that the original insn remains because it is dead
-                anyways.  */
-             /* Delete the insn inside the loop that sets the giv since
-                the giv is now set before (or after) the loop.  */
-             delete_insn (v->insn);
-#endif
-           }
-
-         if (loop_dump_stream)
-           {
-             fprintf (loop_dump_stream, "giv at %d reduced to ",
-                      INSN_UID (v->insn));
-             print_rtl (loop_dump_stream, v->new_reg);
-             fprintf (loop_dump_stream, "\n");
-           }
-       }
-
-      /* All the givs based on the biv bl have been reduced if they
-        merit it.  */
+      /* All the givs based on the biv bl have been reduced if they
+        merit it.  */
 
       /* For each giv not marked as maybe dead that has been combined with a
         second giv, clear any "maybe dead" mark on that second giv.
         v->new_reg will either be or refer to the register of the giv it
         combined with.
 
-        Doing this clearing avoids problems in biv elimination where a
-        giv's new_reg is a complex value that can't be put in the insn but
-        the giv combined with (with a reg as new_reg) is marked maybe_dead.
-        Since the register will be used in either case, we'd prefer it be
-        used from the simpler giv.  */
+        Doing this clearing avoids problems in biv elimination where
+        a giv's new_reg is a complex value that can't be put in the
+        insn but the giv combined with (with a reg as new_reg) is
+        marked maybe_dead.  Since the register will be used in either
+        case, we'd prefer it be used from the simpler giv.  */
 
       for (v = bl->giv; v; v = v->next_iv)
        if (! v->maybe_dead && v->same)
          v->same->maybe_dead = 0;
 
       /* Try to eliminate the biv, if it is a candidate.
-        This won't work if ! all_reduced,
+        This won't work if ! bl->all_reduced,
         since the givs we planned to use might not have been reduced.
 
-        We have to be careful that we didn't initially think we could eliminate
-        this biv because of a giv that we now think may be dead and shouldn't
-        be used as a biv replacement.
+        We have to be careful that we didn't initially think we could
+        eliminate this biv because of a giv that we now think may be
+        dead and shouldn't be used as a biv replacement.
 
         Also, there is the possibility that we may have a giv that looks
         like it can be used to eliminate a biv, but the resulting insn
@@ -4872,7 +4404,7 @@ strength_reduce (loop, insn_count, flags)
         of the occurrences of the biv with a giv, but no harm was done in
         doing so in the rare cases where it can occur.  */
 
-      if (all_reduced == 1 && bl->eliminable
+      if (bl->all_reduced == 1 && bl->eliminable
          && maybe_eliminate_biv (loop, bl, 1, threshold, insn_count))
        {
          /* ?? If we created a new test to bypass the loop entirely,
@@ -4887,35 +4419,9 @@ strength_reduce (loop, insn_count, flags)
             Reversed bivs already have an insn after the loop setting their
             value, so we don't need another one.  We can't calculate the
             proper final value for such a biv here anyways.  */
-         if (final_value != 0 && ! bl->reversed)
-           {
-             rtx insert_before;
-
-             /* If the loop has multiple exits, emit the insn before the
-                loop to ensure that it will always be executed no matter
-                how the loop exits.  Otherwise, emit the insn after the
-                loop, since this is slightly more efficient.  */
-             if (loop->exit_count)
-               insert_before = loop_start;
-             else
-               insert_before = end_insert_before;
-
-             emit_insn_before (gen_move_insn (bl->biv->dest_reg, final_value),
-                               end_insert_before);
-           }
-
-#if 0
-         /* Delete all of the instructions inside the loop which set
-            the biv, as they are all dead.  If is safe to delete them,
-            because an insn setting a biv will never be part of a libcall.  */
-         /* However, deleting them will invalidate the regno_last_uid info,
-            so keeping them around is more convenient.  Final_biv_value
-            will only succeed when there are multiple exits if the biv
-            is dead at each exit, hence it does not matter that the original
-            insn remains, because it is dead anyways.  */
-         for (v = bl->biv; v; v = v->next_iv)
-           delete_insn (v->insn);
-#endif
+         if (bl->final_value && ! bl->reversed)
+             loop_insn_sink_or_swim (loop, gen_move_insn
+                                     (bl->biv->dest_reg, bl->final_value));
 
          if (loop_dump_stream)
            fprintf (loop_dump_stream, "Reg %d: biv eliminated\n",
@@ -4926,7 +4432,7 @@ strength_reduce (loop, insn_count, flags)
   /* Go through all the instructions in the loop, making all the
      register substitutions scheduled in REG_MAP.  */
 
-  for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
+  for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
     if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
        || GET_CODE (p) == CALL_INSN)
       {
@@ -4969,7 +4475,7 @@ strength_reduce (loop, insn_count, flags)
   if ((flags & LOOP_UNROLL)
       || (loop_info->n_iterations > 0
          && unrolled_insn_copies <= insn_count))
-    unroll_loop (loop, insn_count, end_insert_before, 1);
+    unroll_loop (loop, insn_count, 1);
 
 #ifdef HAVE_doloop_end
   if (HAVE_doloop_end && (flags & LOOP_BCT) && flag_branch_on_count_reg)
@@ -4979,10 +4485,7 @@ strength_reduce (loop, insn_count, flags)
   if (loop_dump_stream)
     fprintf (loop_dump_stream, "\n");
 
-egress:
-  VARRAY_FREE (reg_iv_type);
-  VARRAY_FREE (reg_iv_info);
-  free (reg_biv_class);
+  loop_ivs_free (loop);
   if (reg_map)
     free (reg_map);
 }
@@ -4995,6 +4498,7 @@ check_insn_for_bivs (loop, p, not_every_iteration, maybe_multiple)
      int not_every_iteration;
      int maybe_multiple;
 {
+  struct loop_ivs *ivs = LOOP_IVS (loop);
   rtx set;
   rtx dest_reg;
   rtx inc_val;
@@ -5008,7 +4512,7 @@ check_insn_for_bivs (loop, p, not_every_iteration, maybe_multiple)
       dest_reg = SET_DEST (set);
       if (REGNO (dest_reg) < max_reg_before_loop
          && REGNO (dest_reg) >= FIRST_PSEUDO_REGISTER
-         && REG_IV_TYPE (REGNO (dest_reg)) != NOT_BASIC_INDUCT)
+         && REG_IV_TYPE (ivs, REGNO (dest_reg)) != NOT_BASIC_INDUCT)
        {
          if (basic_induction_var (loop, SET_SRC (set),
                                   GET_MODE (SET_SRC (set)),
@@ -5019,14 +4523,14 @@ check_insn_for_bivs (loop, p, not_every_iteration, maybe_multiple)
                 Create and initialize an induction structure for it.  */
 
              struct induction *v
-               = (struct induction *) oballoc (sizeof (struct induction));
+               = (struct induction *) xmalloc (sizeof (struct induction));
 
-             record_biv (v, p, dest_reg, inc_val, mult_val, location,
+             record_biv (loop, v, p, dest_reg, inc_val, mult_val, location,
                          not_every_iteration, maybe_multiple);
-             REG_IV_TYPE (REGNO (dest_reg)) = BASIC_INDUCT;
+             REG_IV_TYPE (ivs, REGNO (dest_reg)) = BASIC_INDUCT;
            }
-         else if (REGNO (dest_reg) < max_reg_before_loop)
-           REG_IV_TYPE (REGNO (dest_reg)) = NOT_BASIC_INDUCT;
+         else if (REGNO (dest_reg) < ivs->n_regs)
+           REG_IV_TYPE (ivs, REGNO (dest_reg)) = NOT_BASIC_INDUCT;
        }
     }
   return p;
@@ -5042,17 +4546,20 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
      int not_every_iteration;
      int maybe_multiple;
 {
+  struct loop_regs *regs = LOOP_REGS (loop);
+
   rtx set;
   /* Look for a general induction variable in a register.  */
   if (GET_CODE (p) == INSN
       && (set = single_set (p))
       && GET_CODE (SET_DEST (set)) == REG
-      && ! VARRAY_CHAR (may_not_optimize, REGNO (SET_DEST (set))))
+      && ! regs->array[REGNO (SET_DEST (set))].may_not_optimize)
     {
       rtx src_reg;
       rtx dest_reg;
       rtx add_val;
       rtx mult_val;
+      rtx ext_val;
       int benefit;
       rtx regnote = 0;
       rtx last_consec_insn;
@@ -5063,11 +4570,11 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
 
       if (/* SET_SRC is a giv.  */
          (general_induction_var (loop, SET_SRC (set), &src_reg, &add_val,
-                                 &mult_val, 0, &benefit, VOIDmode)
+                                 &mult_val, &ext_val, 0, &benefit, VOIDmode)
           /* Equivalent expression is a giv.  */
           || ((regnote = find_reg_note (p, REG_EQUAL, NULL_RTX))
               && general_induction_var (loop, XEXP (regnote, 0), &src_reg,
-                                        &add_val, &mult_val, 0,
+                                        &add_val, &mult_val, &ext_val, 0,
                                         &benefit, VOIDmode)))
          /* Don't try to handle any regs made by loop optimization.
             We have nothing on them in regno_first_uid, etc.  */
@@ -5075,26 +4582,26 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
          /* Don't recognize a BASIC_INDUCT_VAR here.  */
          && dest_reg != src_reg
          /* This must be the only place where the register is set.  */
-         && (VARRAY_INT (n_times_set, REGNO (dest_reg)) == 1
+         && (regs->array[REGNO (dest_reg)].n_times_set == 1
              /* or all sets must be consecutive and make a giv.  */
              || (benefit = consec_sets_giv (loop, benefit, p,
                                             src_reg, dest_reg,
-                                            &add_val, &mult_val,
+                                            &add_val, &mult_val, &ext_val,
                                             &last_consec_insn))))
        {
          struct induction *v
-           = (struct induction *) oballoc (sizeof (struct induction));
+           = (struct induction *) xmalloc (sizeof (struct induction));
 
          /* If this is a library call, increase benefit.  */
          if (find_reg_note (p, REG_RETVAL, NULL_RTX))
            benefit += libcall_benefit (p);
 
          /* Skip the consecutive insns, if there are any.  */
-         if (VARRAY_INT (n_times_set, REGNO (dest_reg)) != 1)
+         if (regs->array[REGNO (dest_reg)].n_times_set != 1)
            p = last_consec_insn;
 
          record_giv (loop, v, p, src_reg, dest_reg, mult_val, add_val,
-                     benefit, DEST_REG, not_every_iteration,
+                     ext_val, benefit, DEST_REG, not_every_iteration,
                      maybe_multiple, NULL_PTR);
 
        }
@@ -5198,6 +4705,7 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
        rtx src_reg;
        rtx add_val;
        rtx mult_val;
+       rtx ext_val;
        int benefit;
 
        /* This code used to disable creating GIVs with mult_val == 1 and
@@ -5206,17 +4714,18 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
           this one would not be seen.   */
 
        if (general_induction_var (loop, XEXP (x, 0), &src_reg, &add_val,
-                                  &mult_val, 1, &benefit, GET_MODE (x)))
+                                  &mult_val, &ext_val, 1, &benefit,
+                                  GET_MODE (x)))
          {
            /* Found one; record it.  */
            struct induction *v
-             = (struct induction *) oballoc (sizeof (struct induction));
+             = (struct induction *) xmalloc (sizeof (struct induction));
 
            record_giv (loop, v, insn, src_reg, addr_placeholder, mult_val,
-                       add_val, benefit, DEST_ADDR, not_every_iteration,
-                       maybe_multiple, &XEXP (x, 0));
+                       add_val, ext_val, benefit, DEST_ADDR,
+                       not_every_iteration, maybe_multiple, &XEXP (x, 0));
 
-           v->mem_mode = GET_MODE (x);
+           v->mem = x;
          }
       }
       return;
@@ -5255,8 +4764,9 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
    executed exactly once per iteration.  */
 
 static void
-record_biv (v, insn, dest_reg, inc_val, mult_val, location,
+record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
            not_every_iteration, maybe_multiple)
+     struct loop *loop;
      struct induction *v;
      rtx insn;
      rtx dest_reg;
@@ -5266,6 +4776,7 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
      int not_every_iteration;
      int maybe_multiple;
 {
+  struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *bl;
 
   v->insn = insn;
@@ -5273,6 +4784,7 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
   v->dest_reg = dest_reg;
   v->mult_val = mult_val;
   v->add_val = inc_val;
+  v->ext_dependant = NULL_RTX;
   v->location = location;
   v->mode = GET_MODE (dest_reg);
   v->always_computable = ! not_every_iteration;
@@ -5282,12 +4794,12 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
   /* Add this to the reg's iv_class, creating a class
      if this is the first incrementation of the reg.  */
 
-  bl = reg_biv_class[REGNO (dest_reg)];
+  bl = REG_IV_CLASS (ivs, REGNO (dest_reg));
   if (bl == 0)
     {
       /* Create and initialize new iv_class.  */
 
-      bl = (struct iv_class *) oballoc (sizeof (struct iv_class));
+      bl = (struct iv_class *) xmalloc (sizeof (struct iv_class));
 
       bl->regno = REGNO (dest_reg);
       bl->biv = 0;
@@ -5297,6 +4809,7 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
 
       /* Set initial value to the reg itself.  */
       bl->initial_value = dest_reg;
+      bl->final_value = 0;
       /* We haven't seen the initializing insn yet */
       bl->init_insn = 0;
       bl->init_set = 0;
@@ -5307,12 +4820,12 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
       bl->reversed = 0;
       bl->total_benefit = 0;
 
-      /* Add this class to loop_iv_list.  */
-      bl->next = loop_iv_list;
-      loop_iv_list = bl;
+      /* Add this class to ivs->list.  */
+      bl->next = ivs->list;
+      ivs->list = bl;
 
       /* Put it in the array of biv register classes.  */
-      reg_biv_class[REGNO (dest_reg)] = bl;
+      REG_IV_CLASS (ivs, REGNO (dest_reg)) = bl;
     }
 
   /* Update IV_CLASS entry for this biv.  */
@@ -5323,23 +4836,7 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
     bl->incremented = 1;
 
   if (loop_dump_stream)
-    {
-      fprintf (loop_dump_stream,
-              "Insn %d: possible biv, reg %d,",
-              INSN_UID (insn), REGNO (dest_reg));
-      if (GET_CODE (inc_val) == CONST_INT)
-       {
-         fprintf (loop_dump_stream, " const =");
-         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (inc_val));
-         fputc ('\n', loop_dump_stream);
-       }
-      else
-       {
-         fprintf (loop_dump_stream, " const = ");
-         print_rtl (loop_dump_stream, inc_val);
-         fprintf (loop_dump_stream, "\n");
-       }
-    }
+    loop_biv_dump (v, loop_dump_stream, 0);
 }
 \f
 /* Fill in the data about one giv.
@@ -5356,19 +4853,20 @@ 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 (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
-           type, not_every_iteration, maybe_multiple, location)
+record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
+           benefit, type, not_every_iteration, maybe_multiple, location)
      const struct loop *loop;
      struct induction *v;
      rtx insn;
      rtx src_reg;
      rtx dest_reg;
-     rtx mult_val, add_val;
+     rtx mult_val, add_val, ext_val;
      int benefit;
      enum g_types type;
      int not_every_iteration, maybe_multiple;
      rtx *location;
 {
+  struct loop_ivs *ivs = LOOP_IVS (loop);
   struct induction *b;
   struct iv_class *bl;
   rtx set = single_set (insn);
@@ -5385,6 +4883,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
   v->dest_reg = dest_reg;
   v->mult_val = mult_val;
   v->add_val = add_val;
+  v->ext_dependant = ext_val;
   v->benefit = benefit;
   v->location = location;
   v->cant_derive = 0;
@@ -5400,8 +4899,6 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
   v->auto_inc_opt = 0;
   v->unrolled = 0;
   v->shared = 0;
-  v->derived_from = 0;
-  v->last_use = 0;
 
   /* The v->always_computable field is used in update_giv_derive, to
      determine whether a giv can be used to derive another giv.  For a
@@ -5427,8 +4924,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
     {
       v->mode = GET_MODE (SET_DEST (set));
 
-      v->lifetime = (uid_luid[REGNO_LAST_UID (REGNO (dest_reg))]
-                    - uid_luid[REGNO_FIRST_UID (REGNO (dest_reg))]);
+      v->lifetime = LOOP_REG_LIFETIME (loop, REGNO (dest_reg));
 
       /* If the lifetime is zero, it means that this register is
         really a dead store.  So mark this as a giv that can be
@@ -5436,13 +4932,13 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
       if (v->lifetime == 0)
        v->ignore = 1;
 
-      REG_IV_TYPE (REGNO (dest_reg)) = GENERAL_INDUCT;
-      REG_IV_INFO (REGNO (dest_reg)) = v;
+      REG_IV_TYPE (ivs, REGNO (dest_reg)) = GENERAL_INDUCT;
+      REG_IV_INFO (ivs, REGNO (dest_reg)) = v;
     }
 
   /* Add the giv to the class of givs computed from one biv.  */
 
-  bl = reg_biv_class[REGNO (src_reg)];
+  bl = REG_IV_CLASS (ivs, REGNO (src_reg));
   if (bl)
     {
       v->next_iv = bl->giv;
@@ -5473,7 +4969,7 @@ record_giv (loop, 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))]
+         && REGNO_LAST_LUID (REGNO (dest_reg))
          < INSN_LUID (loop->end)
          && (! not_every_iteration
              || last_use_this_basic_block (dest_reg, insn)))
@@ -5496,10 +4992,10 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
          for (b = bl->biv; b; b = b->next_iv)
            {
              if (INSN_UID (b->insn) >= max_uid_for_loop
-                 || ((uid_luid[INSN_UID (b->insn)]
-                      >= uid_luid[REGNO_FIRST_UID (REGNO (dest_reg))])
-                     && (uid_luid[INSN_UID (b->insn)]
-                         <= uid_luid[REGNO_LAST_UID (REGNO (dest_reg))])))
+                 || ((INSN_LUID (b->insn)
+                      >= REGNO_FIRST_LUID (REGNO (dest_reg)))
+                     && (INSN_LUID (b->insn)
+                         <= REGNO_LAST_LUID (REGNO (dest_reg)))))
                {
                  v->replaceable = 0;
                  v->not_replaceable = 1;
@@ -5554,51 +5050,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
   }
 
   if (loop_dump_stream)
-    {
-      if (type == DEST_REG)
-       fprintf (loop_dump_stream, "Insn %d: giv reg %d",
-                INSN_UID (insn), REGNO (dest_reg));
-      else
-       fprintf (loop_dump_stream, "Insn %d: dest address",
-                INSN_UID (insn));
-
-      fprintf (loop_dump_stream, " src reg %d benefit %d",
-              REGNO (src_reg), v->benefit);
-      fprintf (loop_dump_stream, " lifetime %d",
-              v->lifetime);
-
-      if (v->replaceable)
-       fprintf (loop_dump_stream, " replaceable");
-
-      if (v->no_const_addval)
-       fprintf (loop_dump_stream, " ncav");
-
-      if (GET_CODE (mult_val) == CONST_INT)
-       {
-         fprintf (loop_dump_stream, " mult ");
-         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (mult_val));
-       }
-      else
-       {
-         fprintf (loop_dump_stream, " mult ");
-         print_rtl (loop_dump_stream, mult_val);
-       }
-
-      if (GET_CODE (add_val) == CONST_INT)
-       {
-         fprintf (loop_dump_stream, " add ");
-         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (add_val));
-       }
-      else
-       {
-         fprintf (loop_dump_stream, " add ");
-         print_rtl (loop_dump_stream, add_val);
-       }
-    }
-
-  if (loop_dump_stream)
-    fprintf (loop_dump_stream, "\n");
-
+    loop_giv_dump (v, loop_dump_stream, 0);
 }
 
 /* All this does is determine whether a giv can be made replaceable because
@@ -5612,10 +5064,11 @@ check_final_value (loop, v)
      const struct loop *loop;
      struct induction *v;
 {
+  struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *bl;
   rtx final_value = 0;
 
-  bl = reg_biv_class[REGNO (v->src_reg)];
+  bl = REG_IV_CLASS (ivs, REGNO (v->src_reg));
 
   /* DEST_ADDR givs will never reach here, because they are always marked
      replaceable above in record_giv.  */
@@ -5629,6 +5082,7 @@ check_final_value (loop, v)
         or all uses follow that insn in the same basic block),
      - its final value can be calculated (this condition is different
        than the one above in record_giv)
+     - it's not used before the it's set
      - no assignments to the biv occur during the giv's lifetime.  */
 
 #if 0
@@ -5640,7 +5094,7 @@ check_final_value (loop, v)
   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;
+      int biv_increment_seen = 0, before_giv_insn = 0;
       rtx p = v->insn;
       rtx last_giv_use;
 
@@ -5670,7 +5124,10 @@ check_final_value (loop, v)
        {
          p = NEXT_INSN (p);
          if (p == loop->end)
-           p = NEXT_INSN (loop->start);
+           {
+             before_giv_insn = 1;
+             p = NEXT_INSN (loop->start);
+           }
          if (p == v->insn)
            break;
 
@@ -5685,10 +5142,10 @@ check_final_value (loop, v)
              if (! biv_increment_seen
                  && reg_set_p (v->src_reg, PATTERN (p)))
                biv_increment_seen = 1;
-               
+
              if (reg_mentioned_p (v->dest_reg, PATTERN (p)))
                {
-                 if (biv_increment_seen)
+                 if (biv_increment_seen || before_giv_insn)
                    {
                      v->replaceable = 0;
                      v->not_replaceable = 1;
@@ -5759,6 +5216,7 @@ update_giv_derive (loop, p)
      const struct loop *loop;
      rtx p;
 {
+  struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *bl;
   struct induction *biv, *giv;
   rtx tem;
@@ -5791,7 +5249,7 @@ update_giv_derive (loop, p)
      subsequent biv update was performed.  If this adjustment cannot be done,
      the giv cannot derive further givs.  */
 
-  for (bl = loop_iv_list; bl; bl = bl->next)
+  for (bl = ivs->list; bl; bl = bl->next)
     for (biv = bl->biv; biv; biv = biv->next_iv)
       if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
          || biv->insn == p)
@@ -5821,20 +5279,21 @@ update_giv_derive (loop, p)
                 be able to compute a compensation.  */
              else if (biv->insn == p)
                {
-                 tem = 0;
+                 rtx ext_val_dummy;
 
+                 tem = 0;
                  if (biv->mult_val == const1_rtx)
                    tem = simplify_giv_expr (loop,
                                             gen_rtx_MULT (giv->mode,
                                                           biv->add_val,
                                                           giv->mult_val),
-                                            &dummy);
+                                            &ext_val_dummy, &dummy);
 
                  if (tem && giv->derive_adjustment)
                    tem = simplify_giv_expr
                      (loop,
                       gen_rtx_PLUS (giv->mode, tem, giv->derive_adjustment),
-                      &dummy);
+                      &ext_val_dummy, &dummy);
 
                  if (tem)
                    giv->derive_adjustment = tem;
@@ -5952,6 +5411,7 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
       insn = p;
       while (1)
        {
+         rtx dest;
          do
            {
              insn = PREV_INSN (insn);
@@ -5964,23 +5424,28 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
          set = single_set (insn);
          if (set == 0)
            break;
-
-         if ((SET_DEST (set) == x
-              || (GET_CODE (SET_DEST (set)) == SUBREG
-                  && (GET_MODE_SIZE (GET_MODE (SET_DEST (set)))
-                      <= UNITS_PER_WORD)
-                  && (GET_MODE_CLASS (GET_MODE (SET_DEST (set)))
-                      == MODE_INT)
-                  && SUBREG_REG (SET_DEST (set)) == x))
-             && basic_induction_var (loop, SET_SRC (set),
-                                     (GET_MODE (SET_SRC (set)) == VOIDmode
-                                      ? GET_MODE (x)
-                                      : GET_MODE (SET_SRC (set))),
-                                     dest_reg, insn,
-                                     inc_val, mult_val, location))
-           return 1;
+         dest = SET_DEST (set);
+         if (dest == x
+             || (GET_CODE (dest) == SUBREG
+                 && (GET_MODE_SIZE (GET_MODE (dest)) <= UNITS_PER_WORD)
+                 && (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT)
+                 && SUBREG_REG (dest) == x))
+           return basic_induction_var (loop, SET_SRC (set),
+                                       (GET_MODE (SET_SRC (set)) == VOIDmode
+                                        ? GET_MODE (x)
+                                        : GET_MODE (SET_SRC (set))),
+                                       dest_reg, insn,
+                                       inc_val, mult_val, location);
+
+         while (GET_CODE (dest) == SIGN_EXTRACT
+                || GET_CODE (dest) == ZERO_EXTRACT
+                || GET_CODE (dest) == SUBREG
+                || GET_CODE (dest) == STRICT_LOW_PART)
+           dest = XEXP (dest, 0);
+         if (dest == x)
+           break;
        }
-      /* ... fall through ...  */
+      /* Fall through.  */
 
       /* Can accept constant setting of biv only when inside inner most loop.
         Otherwise, a biv of an inner loop may be incorrectly recognized
@@ -5998,7 +5463,7 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
       if (loop->level == 1
          && GET_MODE_CLASS (mode) != MODE_CC
          && GET_MODE_CLASS (GET_MODE (dest_reg)) != MODE_CC)
-       {
+       {
          /* Possible bug here?  Perhaps we don't know the mode of X.  */
          *inc_val = convert_modes (GET_MODE (dest_reg), mode, x, 0);
          *mult_val = const0_rtx;
@@ -6054,34 +5519,30 @@ basic_induction_var (loop, 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 (loop, x, src_reg, add_val, mult_val, is_addr,
-                      pbenefit, addr_mode)
+general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
+                      is_addr, pbenefit, addr_mode)
      const struct loop *loop;
      rtx x;
      rtx *src_reg;
      rtx *add_val;
      rtx *mult_val;
+     rtx *ext_val;
      int is_addr;
      int *pbenefit;
      enum machine_mode addr_mode;
 {
+  struct loop_ivs *ivs = LOOP_IVS (loop);
   rtx orig_x = x;
-  char *storage;
 
   /* If this is an invariant, forget it, it isn't a giv.  */
   if (loop_invariant_p (loop, x) == 1)
     return 0;
 
-  /* See if the expression could be a giv and get its form.
-     Mark our place on the obstack in case we don't find a giv.  */
-  storage = (char *) oballoc (0);
   *pbenefit = 0;
-  x = simplify_giv_expr (loop, x, pbenefit);
+  *ext_val = NULL_RTX;
+  x = simplify_giv_expr (loop, x, ext_val, pbenefit);
   if (x == 0)
-    {
-      obfree (storage);
-      return 0;
-    }
+    return 0;
 
   switch (GET_CODE (x))
     {
@@ -6090,7 +5551,7 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, is_addr,
       /* Since this is now an invariant and wasn't before, it must be a giv
         with MULT_VAL == 0.  It doesn't matter which BIV we associate this
         with.  */
-      *src_reg = loop_iv_list->biv->dest_reg;
+      *src_reg = ivs->list->biv->dest_reg;
       *mult_val = const0_rtx;
       *add_val = x;
       break;
@@ -6169,15 +5630,16 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, is_addr,
 
 static rtx sge_plus PARAMS ((enum machine_mode, rtx, rtx));
 static rtx sge_plus_constant PARAMS ((rtx, rtx));
-static int cmp_combine_givs_stats PARAMS ((const PTR, const PTR));
-static int cmp_recombine_givs_stats PARAMS ((const PTR, const PTR));
 
 static rtx
-simplify_giv_expr (loop, x, benefit)
+simplify_giv_expr (loop, x, ext_val, benefit)
      const struct loop *loop;
      rtx x;
+     rtx *ext_val;
      int *benefit;
 {
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  struct loop_regs *regs = LOOP_REGS (loop);
   enum machine_mode mode = GET_MODE (x);
   rtx arg0, arg1;
   rtx tem;
@@ -6192,8 +5654,8 @@ simplify_giv_expr (loop, x, benefit)
   switch (GET_CODE (x))
     {
     case PLUS:
-      arg0 = simplify_giv_expr (loop, XEXP (x, 0), benefit);
-      arg1 = simplify_giv_expr (loop, XEXP (x, 1), benefit);
+      arg0 = simplify_giv_expr (loop, XEXP (x, 0), ext_val, benefit);
+      arg1 = simplify_giv_expr (loop, XEXP (x, 1), ext_val, benefit);
       if (arg0 == 0 || arg1 == 0)
        return NULL_RTX;
 
@@ -6245,7 +5707,7 @@ simplify_giv_expr (loop, x, benefit)
                                               gen_rtx_PLUS (mode,
                                                             XEXP (arg0, 1),
                                                             arg1)),
-                                benefit);
+                                ext_val, benefit);
 
          default:
            abort ();
@@ -6271,7 +5733,7 @@ simplify_giv_expr (loop, x, benefit)
                                             gen_rtx_PLUS (mode, arg0,
                                                           XEXP (arg1, 0)),
                                             XEXP (arg1, 1)),
-                              benefit);
+                              ext_val, benefit);
 
       /* Now must have MULT + MULT.  Distribute if same biv, else not giv.  */
       if (GET_CODE (arg0) != MULT || GET_CODE (arg1) != MULT)
@@ -6286,7 +5748,7 @@ simplify_giv_expr (loop, x, benefit)
                                              gen_rtx_PLUS (mode,
                                                            XEXP (arg0, 1),
                                                            XEXP (arg1, 1))),
-                               benefit);
+                               ext_val, benefit);
 
     case MINUS:
       /* Handle "a - b" as "a + b * (-1)".  */
@@ -6296,11 +5758,11 @@ simplify_giv_expr (loop, x, benefit)
                                              gen_rtx_MULT (mode,
                                                            XEXP (x, 1),
                                                            constm1_rtx)),
-                               benefit);
+                               ext_val, benefit);
 
     case MULT:
-      arg0 = simplify_giv_expr (loop, XEXP (x, 0), benefit);
-      arg1 = simplify_giv_expr (loop, XEXP (x, 1), benefit);
+      arg0 = simplify_giv_expr (loop, XEXP (x, 0), ext_val, benefit);
+      arg1 = simplify_giv_expr (loop, XEXP (x, 1), ext_val, benefit);
       if (arg0 == 0 || arg1 == 0)
        return NULL_RTX;
 
@@ -6346,7 +5808,7 @@ simplify_giv_expr (loop, x, benefit)
                                                                    XEXP (arg0,
                                                                          1),
                                                                    arg1)),
-                                       benefit);
+                                       ext_val, benefit);
            }
          /* Porpagate the MULT expressions to the intermost nodes.  */
          else if (GET_CODE (arg0) == PLUS)
@@ -6362,7 +5824,7 @@ simplify_giv_expr (loop, x, benefit)
                                                                    XEXP (arg0,
                                                                          1),
                                                                    arg1)),
-                                       benefit);
+                                       ext_val, benefit);
            }
          return gen_rtx_USE (mode, gen_rtx_MULT (mode, arg0, arg1));
 
@@ -6374,7 +5836,7 @@ simplify_giv_expr (loop, x, benefit)
                                                  gen_rtx_MULT (mode,
                                                                XEXP (arg0, 1),
                                                                arg1)),
-                                   benefit);
+                                   ext_val, benefit);
 
        case PLUS:
          /* (a + invar_1) * invar_2.  Distribute.  */
@@ -6386,7 +5848,7 @@ simplify_giv_expr (loop, x, benefit)
                                                  gen_rtx_MULT (mode,
                                                                XEXP (arg0, 1),
                                                                arg1)),
-                                   benefit);
+                                   ext_val, benefit);
 
        default:
          abort ();
@@ -6403,13 +5865,13 @@ simplify_giv_expr (loop, x, benefit)
                                         XEXP (x, 0),
                                         GEN_INT ((HOST_WIDE_INT) 1
                                                  << INTVAL (XEXP (x, 1)))),
-                          benefit);
+                          ext_val, benefit);
 
     case NEG:
       /* "-a" is "a * (-1)" */
       return simplify_giv_expr (loop,
                                gen_rtx_MULT (mode, XEXP (x, 0), constm1_rtx),
-                               benefit);
+                               ext_val, benefit);
 
     case NOT:
       /* "~a" is "-a - 1". Silly, but easy.  */
@@ -6417,29 +5879,59 @@ simplify_giv_expr (loop, x, benefit)
                                gen_rtx_MINUS (mode,
                                               gen_rtx_NEG (mode, XEXP (x, 0)),
                                               const1_rtx),
-                               benefit);
+                               ext_val, benefit);
 
     case USE:
       /* Already in proper form for invariant.  */
       return x;
 
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+    case TRUNCATE:
+      /* Conditionally recognize extensions of simple IVs.  After we've
+        computed loop traversal counts and verified the range of the
+        source IV, we'll reevaluate this as a GIV.  */
+      if (*ext_val == NULL_RTX)
+       {
+         arg0 = simplify_giv_expr (loop, XEXP (x, 0), ext_val, benefit);
+         if (arg0 && *ext_val == NULL_RTX && GET_CODE (arg0) == REG)
+           {
+             *ext_val = gen_rtx_fmt_e (GET_CODE (x), mode, arg0);
+             return arg0;
+           }
+       }
+      goto do_default;
+
     case REG:
       /* If this is a new register, we can't deal with it.  */
       if (REGNO (x) >= max_reg_before_loop)
        return 0;
 
       /* Check for biv or giv.  */
-      switch (REG_IV_TYPE (REGNO (x)))
+      switch (REG_IV_TYPE (ivs, REGNO (x)))
        {
        case BASIC_INDUCT:
          return x;
        case GENERAL_INDUCT:
          {
-           struct induction *v = REG_IV_INFO (REGNO (x));
+           struct induction *v = REG_IV_INFO (ivs, REGNO (x));
 
            /* Form expression from giv and add benefit.  Ensure this giv
               can derive another and subtract any needed adjustment if so.  */
-           *benefit += v->benefit;
+
+           /* Increasing the benefit here is risky.  The only case in which it
+              is arguably correct is if this is the only use of V.  In other
+              cases, this will artificially inflate the benefit of the current
+              giv, and lead to suboptimal code.  Thus, it is disabled, since
+              potentially not reducing an only marginally beneficial giv is
+              less harmful than reducing many givs that are not really
+              beneficial.  */
+           {
+             rtx single_use = regs->array[REGNO (x)].single_usage;
+             if (single_use && single_use != const0_rtx)
+               *benefit += v->benefit;
+           }
+
            if (v->cant_derive)
              return 0;
 
@@ -6449,18 +5941,31 @@ simplify_giv_expr (loop, x, benefit)
 
            if (v->derive_adjustment)
              tem = gen_rtx_MINUS (mode, tem, v->derive_adjustment);
-           return simplify_giv_expr (loop, tem, benefit);
+           arg0 = simplify_giv_expr (loop, tem, ext_val, benefit);
+           if (*ext_val)
+             {
+               if (!v->ext_dependant)
+                 return arg0;
+             }
+           else
+             {
+               *ext_val = v->ext_dependant;
+               return arg0;
+             }
+           return 0;
          }
 
        default:
+       do_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 (loop_invariant_p (loop, x) == 1)
            {
              struct movable *m;
+             struct loop_movables *movables = LOOP_MOVABLES (loop);
 
-             for (m = the_movables; m; m = m->next)
+             for (m = movables->head; m; m = m->next)
                if (rtx_equal_p (x, m->set_dest))
                  {
                    /* Ok, we found a match.  Substitute and simplify.  */
@@ -6469,7 +5974,7 @@ simplify_giv_expr (loop, x, benefit)
                       this one is going away.  */
                    if (m->match)
                      return simplify_giv_expr (loop, m->match->set_dest,
-                                               benefit);
+                                               ext_val, benefit);
 
                    /* If consec is non-zero, this is a member of a group of
                       instructions that were moved together.  We handle this
@@ -6479,7 +5984,11 @@ simplify_giv_expr (loop, x, benefit)
                      {
                        int i = m->consec;
                        tem = m->insn;
-                       do { tem = NEXT_INSN (tem); } while (--i > 0);
+                       do
+                         {
+                           tem = NEXT_INSN (tem);
+                         }
+                       while (--i > 0);
 
                        tem = find_reg_note (tem, REG_EQUAL, NULL_RTX);
                        if (tem)
@@ -6503,17 +6012,18 @@ simplify_giv_expr (loop, x, benefit)
                            || GET_CODE (tem) == CONST_INT
                            || GET_CODE (tem) == SYMBOL_REF)
                          {
-                           tem = simplify_giv_expr (loop, tem, benefit);
+                           tem = simplify_giv_expr (loop, tem, ext_val,
+                                                    benefit);
                            if (tem)
                              return tem;
                          }
                        else if (GET_CODE (tem) == CONST
-                           && GET_CODE (XEXP (tem, 0)) == PLUS
-                           && GET_CODE (XEXP (XEXP (tem, 0), 0)) == SYMBOL_REF
-                           && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)
+                                && GET_CODE (XEXP (tem, 0)) == PLUS
+                                && GET_CODE (XEXP (XEXP (tem, 0), 0)) == SYMBOL_REF
+                                && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)
                          {
                            tem = simplify_giv_expr (loop, XEXP (tem, 0),
-                                                    benefit);
+                                                    ext_val, benefit);
                            if (tem)
                              return tem;
                          }
@@ -6618,7 +6128,7 @@ sge_plus (mode, x, y)
 
 static int
 consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
-                add_val, mult_val, last_consec_insn)
+                add_val, mult_val, ext_val, last_consec_insn)
      const struct loop *loop;
      int first_benefit;
      rtx p;
@@ -6626,8 +6136,11 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
      rtx dest_reg;
      rtx *add_val;
      rtx *mult_val;
+     rtx *ext_val;
      rtx *last_consec_insn;
 {
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  struct loop_regs *regs = LOOP_REGS (loop);
   int count;
   enum rtx_code code;
   int benefit;
@@ -6641,19 +6154,24 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
      general_induction_var below, so we can allocate it on our stack.
      If this is a giv, our caller will replace the induct var entry with
      a new induction structure.  */
-  struct induction *v
-    = (struct induction *) alloca (sizeof (struct induction));
+  struct induction *v;
+
+  if (REG_IV_TYPE (ivs, REGNO (dest_reg)) != UNKNOWN_INDUCT)
+    return 0;
+
+  v = (struct induction *) alloca (sizeof (struct induction));
   v->src_reg = src_reg;
   v->mult_val = *mult_val;
   v->add_val = *add_val;
   v->benefit = first_benefit;
   v->cant_derive = 0;
   v->derive_adjustment = 0;
+  v->ext_dependant = NULL_RTX;
 
-  REG_IV_TYPE (REGNO (dest_reg)) = GENERAL_INDUCT;
-  REG_IV_INFO (REGNO (dest_reg)) = v;
+  REG_IV_TYPE (ivs, REGNO (dest_reg)) = GENERAL_INDUCT;
+  REG_IV_INFO (ivs, REGNO (dest_reg)) = v;
 
-  count = VARRAY_INT (n_times_set, REGNO (dest_reg)) - 1;
+  count = regs->array[REGNO (dest_reg)].n_times_set - 1;
 
   while (count > 0)
     {
@@ -6669,12 +6187,13 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
          && GET_CODE (SET_DEST (set)) == REG
          && SET_DEST (set) == dest_reg
          && (general_induction_var (loop, SET_SRC (set), &src_reg,
-                                    add_val, mult_val, 0, &benefit, VOIDmode)
+                                    add_val, mult_val, ext_val, 0,
+                                    &benefit, VOIDmode)
              /* Giv created by equivalent expression.  */
              || ((temp = find_reg_note (p, REG_EQUAL, NULL_RTX))
                  && general_induction_var (loop, XEXP (temp, 0), &src_reg,
-                                           add_val, mult_val, 0, &benefit,
-                                           VOIDmode)))
+                                           add_val, mult_val, ext_val, 0,
+                                           &benefit, VOIDmode)))
          && src_reg == v->src_reg)
        {
          if (find_reg_note (p, REG_RETVAL, NULL_RTX))
@@ -6683,7 +6202,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
          count--;
          v->mult_val = *mult_val;
          v->add_val = *add_val;
-         v->benefit = benefit;
+         v->benefit += benefit;
        }
       else if (code != NOTE)
        {
@@ -6696,11 +6215,12 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
              && CONSTANT_P (SET_SRC (set)))
            continue;
 
-         REG_IV_TYPE (REGNO (dest_reg)) = UNKNOWN_INDUCT;
+         REG_IV_TYPE (ivs, REGNO (dest_reg)) = UNKNOWN_INDUCT;
          return 0;
        }
     }
 
+  REG_IV_TYPE (ivs, REGNO (dest_reg)) = UNKNOWN_INDUCT;
   *last_consec_insn = p;
   return v->benefit;
 }
@@ -6768,7 +6288,7 @@ express_from_1 (a, b, mult)
        a = ra, b = ob;
       else
        {
-          /* Indicates an extra register in B.  Strip one level from B and
+         /* Indicates an extra register in B.  Strip one level from B and
             recurse, hoping B was the higher order expression.  */
          ob = express_from_1 (a, ob, mult);
          if (ob == NULL_RTX)
@@ -6904,25 +6424,36 @@ static rtx
 combine_givs_p (g1, g2)
      struct induction *g1, *g2;
 {
-  rtx tem = express_from (g1, g2);
+  rtx comb, ret;
+
+  /* With the introduction of ext dependant givs, we must care for modes.
+     G2 must not use a wider mode than G1.  */
+  if (GET_MODE_SIZE (g1->mode) < GET_MODE_SIZE (g2->mode))
+    return NULL_RTX;
+
+  ret = comb = express_from (g1, g2);
+  if (comb == NULL_RTX)
+    return NULL_RTX;
+  if (g1->mode != g2->mode)
+    ret = gen_lowpart (g2->mode, comb);
 
   /* If these givs are identical, they can be combined.  We use the results
      of express_from because the addends are not in a canonical form, so
      rtx_equal_p is a weaker test.  */
   /* But don't combine a DEST_REG giv with a DEST_ADDR giv; we want the
      combination to be the other way round.  */
-  if (tem == g1->dest_reg
+  if (comb == g1->dest_reg
       && (g1->giv_type == DEST_REG || g2->giv_type == DEST_ADDR))
     {
-      return g1->dest_reg;
+      return ret;
     }
 
   /* If G2 can be expressed as a function of G1 and that function is valid
      as an address and no more expensive than using a register for G2,
      the expression of G2 in terms of G1 can be used.  */
-  if (tem != NULL_RTX
+  if (ret != NULL_RTX
       && g2->giv_type == DEST_ADDR
-      && memory_address_p (g2->mem_mode, tem)
+      && memory_address_p (GET_MODE (g2->mem), ret)
       /* ??? Looses, especially with -fforce-addr, where *g2->location
         will always be a register, and so anything more complicated
         gets discarded.  */
@@ -6935,12 +6466,198 @@ combine_givs_p (g1, g2)
 #endif
       )
     {
-      return tem;
+      return ret;
     }
 
   return NULL_RTX;
 }
 \f
+/* Check each extension dependant giv in this class to see if its
+   root biv is safe from wrapping in the interior mode, which would
+   make the giv illegal.  */
+
+static void
+check_ext_dependant_givs (bl, loop_info)
+     struct iv_class *bl;
+     struct loop_info *loop_info;
+{
+  int ze_ok = 0, se_ok = 0, info_ok = 0;
+  enum machine_mode biv_mode = GET_MODE (bl->biv->src_reg);
+  HOST_WIDE_INT start_val;
+  unsigned HOST_WIDE_INT u_end_val = 0;
+  unsigned HOST_WIDE_INT u_start_val = 0;
+  rtx incr = pc_rtx;
+  struct induction *v;
+
+  /* Make sure the iteration data is available.  We must have
+     constants in order to be certain of no overflow.  */
+  /* ??? An unknown iteration count with an increment of +-1
+     combined with friendly exit tests of against an invariant
+     value is also ameanable to optimization.  Not implemented.  */
+  if (loop_info->n_iterations > 0
+      && bl->initial_value
+      && GET_CODE (bl->initial_value) == CONST_INT
+      && (incr = biv_total_increment (bl))
+      && GET_CODE (incr) == CONST_INT
+      /* Make sure the host can represent the arithmetic.  */
+      && HOST_BITS_PER_WIDE_INT >= GET_MODE_BITSIZE (biv_mode))
+    {
+      unsigned HOST_WIDE_INT abs_incr, total_incr;
+      HOST_WIDE_INT s_end_val;
+      int neg_incr;
+
+      info_ok = 1;
+      start_val = INTVAL (bl->initial_value);
+      u_start_val = start_val;
+
+      neg_incr = 0, abs_incr = INTVAL (incr);
+      if (INTVAL (incr) < 0)
+       neg_incr = 1, abs_incr = -abs_incr;
+      total_incr = abs_incr * loop_info->n_iterations;
+
+      /* Check for host arithmatic overflow.  */
+      if (total_incr / loop_info->n_iterations == abs_incr)
+       {
+         unsigned HOST_WIDE_INT u_max;
+         HOST_WIDE_INT s_max;
+
+         u_end_val = start_val + (neg_incr ? -total_incr : total_incr);
+         s_end_val = u_end_val;
+         u_max = GET_MODE_MASK (biv_mode);
+         s_max = u_max >> 1;
+
+         /* Check zero extension of biv ok.  */
+         if (start_val >= 0
+             /* Check for host arithmatic overflow.  */
+             && (neg_incr
+                 ? u_end_val < u_start_val
+                 : u_end_val > u_start_val)
+             /* Check for target arithmetic overflow.  */
+             && (neg_incr
+                 ? 1 /* taken care of with host overflow */
+                 : u_end_val <= u_max))
+           {
+             ze_ok = 1;
+           }
+
+         /* Check sign extension of biv ok.  */
+         /* ??? While it is true that overflow with signed and pointer
+            arithmetic is undefined, I fear too many programmers don't
+            keep this fact in mind -- myself included on occasion.
+            So leave alone with the signed overflow optimizations.  */
+         if (start_val >= -s_max - 1
+             /* Check for host arithmatic overflow.  */
+             && (neg_incr
+                 ? s_end_val < start_val
+                 : s_end_val > start_val)
+             /* Check for target arithmetic overflow.  */
+             && (neg_incr
+                 ? s_end_val >= -s_max - 1
+                 : s_end_val <= s_max))
+           {
+             se_ok = 1;
+           }
+       }
+    }
+
+  /* Invalidate givs that fail the tests.  */
+  for (v = bl->giv; v; v = v->next_iv)
+    if (v->ext_dependant)
+      {
+       enum rtx_code code = GET_CODE (v->ext_dependant);
+       int ok = 0;
+
+       switch (code)
+         {
+         case SIGN_EXTEND:
+           ok = se_ok;
+           break;
+         case ZERO_EXTEND:
+           ok = ze_ok;
+           break;
+
+         case TRUNCATE:
+           /* We don't know whether this value is being used as either
+              signed or unsigned, so to safely truncate we must satisfy
+              both.  The initial check here verifies the BIV itself;
+              once that is successful we may check its range wrt the
+              derived GIV.  */
+           if (se_ok && ze_ok)
+             {
+               enum machine_mode outer_mode = GET_MODE (v->ext_dependant);
+               unsigned HOST_WIDE_INT max = GET_MODE_MASK (outer_mode) >> 1;
+
+               /* We know from the above that both endpoints are nonnegative,
+                  and that there is no wrapping.  Verify that both endpoints
+                  are within the (signed) range of the outer mode.  */
+               if (u_start_val <= max && u_end_val <= max)
+                 ok = 1;
+             }
+           break;
+
+         default:
+           abort ();
+         }
+
+       if (ok)
+         {
+           if (loop_dump_stream)
+             {
+               fprintf (loop_dump_stream,
+                        "Verified ext dependant giv at %d of reg %d\n",
+                        INSN_UID (v->insn), bl->regno);
+             }
+         }
+       else
+         {
+           if (loop_dump_stream)
+             {
+               const char *why;
+
+               if (info_ok)
+                 why = "biv iteration values overflowed";
+               else
+                 {
+                   if (incr == pc_rtx)
+                     incr = biv_total_increment (bl);
+                   if (incr == const1_rtx)
+                     why = "biv iteration info incomplete; incr by 1";
+                   else
+                     why = "biv iteration info incomplete";
+                 }
+
+               fprintf (loop_dump_stream,
+                        "Failed ext dependant giv at %d, %s\n",
+                        INSN_UID (v->insn), why);
+             }
+           v->ignore = 1;
+         }
+      }
+}
+
+/* Generate a version of VALUE in a mode appropriate for initializing V.  */
+
+rtx
+extend_value_for_giv (v, value)
+     struct induction *v;
+     rtx value;
+{
+  rtx ext_dep = v->ext_dependant;
+
+  if (! ext_dep)
+    return value;
+
+  /* Recall that check_ext_dependant_givs verified that the known bounds
+     of a biv did not overflow or wrap with respect to the extension for
+     the giv.  Therefore, constants need no additional adjustment.  */
+  if (CONSTANT_P (value) && GET_MODE (value) == VOIDmode)
+    return value;
+
+  /* Otherwise, we must adjust the value to compensate for the
+     differing modes of the biv and the giv.  */
+  return gen_rtx_fmt_e (GET_CODE (ext_dep), GET_MODE (ext_dep), value);
+}
+\f
 struct combine_givs_stats
 {
   int giv_number;
@@ -6970,7 +6687,8 @@ cmp_combine_givs_stats (xp, yp)
    giv.  Also, update BENEFIT and related fields for cost/benefit analysis.  */
 
 static void
-combine_givs (bl)
+combine_givs (regs, bl)
+     struct loop_regs *regs;
      struct iv_class *bl;
 {
   /* Additional benefit to add for being combined multiple times.  */
@@ -7012,592 +6730,158 @@ combine_givs (bl)
         DEST_ADDR targets on hosts with reg+reg addressing, though it can
         be seen elsewhere as well.  */
       if (g1->giv_type == DEST_REG
-         && (single_use = VARRAY_RTX (reg_single_usage, REGNO (g1->dest_reg)))
-         && single_use != const0_rtx)
-       continue;
-
-      this_benefit = g1->benefit;
-      /* Add an additional weight for zero addends.  */
-      if (g1->no_const_addval)
-       this_benefit += 1;
-
-      for (j = 0; j < giv_count; j++)
-       {
-         rtx this_combine;
-
-         g2 = giv_array[j];
-         if (g1 != g2
-             && (this_combine = combine_givs_p (g1, g2)) != NULL_RTX)
-           {
-             can_combine[i * giv_count + j] = this_combine;
-             this_benefit += g2->benefit + extra_benefit;
-           }
-       }
-      stats[i].total_benefit = this_benefit;
-    }
-
-  /* Iterate, combining until we can't.  */
-restart:
-  qsort (stats, giv_count, sizeof (*stats), cmp_combine_givs_stats);
-
-  if (loop_dump_stream)
-    {
-      fprintf (loop_dump_stream, "Sorted combine statistics:\n");
-      for (k = 0; k < giv_count; k++)
-       {
-         g1 = giv_array[stats[k].giv_number];
-         if (!g1->combined_with && !g1->same)
-           fprintf (loop_dump_stream, " {%d, %d}",
-                    INSN_UID (giv_array[stats[k].giv_number]->insn),
-                    stats[k].total_benefit);
-       }
-      putc ('\n', loop_dump_stream);
-    }
-
-  for (k = 0; k < giv_count; k++)
-    {
-      int g1_add_benefit = 0;
-
-      i = stats[k].giv_number;
-      g1 = giv_array[i];
-
-      /* If it has already been combined, skip.  */
-      if (g1->combined_with || g1->same)
-       continue;
-
-      for (j = 0; j < giv_count; j++)
-       {
-         g2 = giv_array[j];
-         if (g1 != g2 && can_combine[i * giv_count + j]
-             /* If it has already been combined, skip.  */
-             && ! g2->same && ! g2->combined_with)
-           {
-             int l;
-
-             g2->new_reg = can_combine[i * giv_count + j];
-             g2->same = g1;
-             g1->combined_with++;
-             g1->lifetime += g2->lifetime;
-
-             g1_add_benefit += g2->benefit;
-
-             /* ??? The new final_[bg]iv_value code does a much better job
-                of finding replaceable giv's, and hence this code may no
-                longer be necessary.  */
-             if (! g2->replaceable && REG_USERVAR_P (g2->dest_reg))
-               g1_add_benefit -= copy_cost;
-
-             /* To help optimize the next set of combinations, remove
-                this giv from the benefits of other potential mates.  */
-             for (l = 0; l < giv_count; ++l)
-               {
-                 int m = stats[l].giv_number;
-                 if (can_combine[m * giv_count + j])
-                   stats[l].total_benefit -= g2->benefit + extra_benefit;
-               }
-
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream,
-                        "giv at %d combined with giv at %d\n",
-                        INSN_UID (g2->insn), INSN_UID (g1->insn));
-           }
-       }
-
-      /* To help optimize the next set of combinations, remove
-        this giv from the benefits of other potential mates.  */
-      if (g1->combined_with)
-       {
-         for (j = 0; j < giv_count; ++j)
-           {
-             int m = stats[j].giv_number;
-             if (can_combine[m * giv_count + i])
-               stats[j].total_benefit -= g1->benefit + extra_benefit;
-           }
-
-         g1->benefit += g1_add_benefit;
-
-         /* We've finished with this giv, and everything it touched.
-            Restart the combination so that proper weights for the
-            rest of the givs are properly taken into account.  */
-         /* ??? Ideally we would compact the arrays at this point, so
-            as to not cover old ground.  But sanely compacting
-            can_combine is tricky.  */
-         goto restart;
-       }
-    }
-
-  /* Clean up.  */
-  free (stats);
-  free (can_combine);
-}
-\f
-struct recombine_givs_stats
-{
-  int giv_number;
-  int start_luid, end_luid;
-};
-
-/* Used below as comparison function for qsort.  We want a ascending luid
-   when scanning the array starting at the end, thus the arguments are
-   used in reverse.  */
-static int
-cmp_recombine_givs_stats (xp, yp)
-     const PTR xp;
-     const PTR yp;
-{
-  const struct recombine_givs_stats * const x =
-    (const struct recombine_givs_stats *) xp;
-  const struct recombine_givs_stats * const y =
-    (const struct recombine_givs_stats *) yp;
-  int d;
-  d = y->start_luid - x->start_luid;
-  /* Stabilize the sort.  */
-  if (!d)
-    d = y->giv_number - x->giv_number;
-  return d;
-}
-
-/* Scan X, which is a part of INSN, for the end of life of a giv.  Also
-   look for the start of life of a giv where the start has not been seen
-   yet to unlock the search for the end of its life.
-   Only consider givs that belong to BIV.
-   Return the total number of lifetime ends that have been found.  */
-static int
-find_life_end (x, stats, insn, biv)
-     rtx x, insn, biv;
-     struct recombine_givs_stats *stats;
-{
-  enum rtx_code code;
-  const char *fmt;
-  int i, j;
-  int retval;
-
-  code = GET_CODE (x);
-  switch (code)
-    {
-    case SET:
-      {
-       rtx reg = SET_DEST (x);
-       if (GET_CODE (reg) == REG)
-         {
-           int regno = REGNO (reg);
-           struct induction *v = REG_IV_INFO (regno);
-
-           if (REG_IV_TYPE (regno) == GENERAL_INDUCT
-               && ! v->ignore
-               && v->src_reg == biv
-               && stats[v->ix].end_luid <= 0)
-             {
-               /* If we see a 0 here for end_luid, it means that we have
-                  scanned the entire loop without finding any use at all.
-                  We must not predicate this code on a start_luid match
-                  since that would make the test fail for givs that have
-                  been hoisted out of inner loops.  */
-               if (stats[v->ix].end_luid == 0)
-                 {
-                   stats[v->ix].end_luid = stats[v->ix].start_luid;
-                   return 1 + find_life_end (SET_SRC (x), stats, insn, biv);
-                 }
-               else if (stats[v->ix].start_luid == INSN_LUID (insn))
-                 stats[v->ix].end_luid = 0;
-             }
-           return find_life_end (SET_SRC (x), stats, insn, biv);
-         }
-       break;
-      }
-    case REG:
-      {
-       int regno = REGNO (x);
-       struct induction *v = REG_IV_INFO (regno);
-
-       if (REG_IV_TYPE (regno) == GENERAL_INDUCT
-           && ! v->ignore
-           && v->src_reg == biv
-           && stats[v->ix].end_luid == 0)
-         {
-           while (INSN_UID (insn) >= max_uid_for_loop)
-             insn = NEXT_INSN (insn);
-           stats[v->ix].end_luid = INSN_LUID (insn);
-           return 1;
-         }
-       return 0;
-      }
-    case LABEL_REF:
-    case CONST_DOUBLE:
-    case CONST_INT:
-    case CONST:
-      return 0;
-    default:
-      break;
-    }
-  fmt = GET_RTX_FORMAT (code);
-  retval = 0;
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    {
-      if (fmt[i] == 'e')
-       retval += find_life_end (XEXP (x, i), stats, insn, biv);
-
-      else if (fmt[i] == 'E')
-       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-         retval += find_life_end (XVECEXP (x, i, j), stats, insn, biv);
-    }
-  return retval;
-}
-
-/* For each giv that has been combined with another, look if
-   we can combine it with the most recently used one instead.
-   This tends to shorten giv lifetimes, and helps the next step:
-   try to derive givs from other givs.  */
-static void
-recombine_givs (loop, bl, unroll_p)
-     const struct loop *loop;
-     struct iv_class *bl;
-     int unroll_p;
-{
-  struct induction *v, **giv_array, *last_giv;
-  struct recombine_givs_stats *stats;
-  int giv_count;
-  int i, rescan;
-  int ends_need_computing;
-
-  for (giv_count = 0, v = bl->giv; v; v = v->next_iv)
-    {
-      if (! v->ignore)
-       giv_count++;
-    }
-  giv_array
-    = (struct induction **) xmalloc (giv_count * sizeof (struct induction *));
-  stats = (struct recombine_givs_stats *) xmalloc (giv_count * sizeof *stats);
-
-  /* Initialize stats and set up the ix field for each giv in stats to name
-     the corresponding index into stats.  */
-  for (i = 0, v = bl->giv; v; v = v->next_iv)
-    {
-      rtx p;
-
-      if (v->ignore)
-       continue;
-      giv_array[i] = v;
-      stats[i].giv_number = i;
-      /* If this giv has been hoisted out of an inner loop, use the luid of
-        the previous insn.  */
-      for (p = v->insn; INSN_UID (p) >= max_uid_for_loop; )
-       p = PREV_INSN (p);
-      stats[i].start_luid = INSN_LUID (p);
-      i++;
-    }
-
-  qsort (stats, giv_count, sizeof (*stats), cmp_recombine_givs_stats);
-
-  /* Set up the ix field for each giv in stats to name
-     the corresponding index into stats, and
-     do the actual most-recently-used recombination.  */
-  for (last_giv = 0, i = giv_count - 1; i >= 0; i--)
-    {
-      v = giv_array[stats[i].giv_number];
-      v->ix = i;
-      if (v->same)
-       {
-         struct induction *old_same = v->same;
-         rtx new_combine;
-
-         /* combine_givs_p actually says if we can make this transformation.
-            The other tests are here only to avoid keeping a giv alive
-            that could otherwise be eliminated.  */
-         if (last_giv
-             && ((old_same->maybe_dead && ! old_same->combined_with)
-                 || ! last_giv->maybe_dead
-                 || last_giv->combined_with)
-             && (new_combine = combine_givs_p (last_giv, v)))
-           {
-             old_same->combined_with--;
-             v->new_reg = new_combine;
-             v->same = last_giv;
-             last_giv->combined_with++;
-             /* No need to update lifetimes / benefits here since we have
-                already decided what to reduce.  */
-
-             if (loop_dump_stream)
-               {
-                 fprintf (loop_dump_stream,
-                          "giv at %d recombined with giv at %d as ",
-                          INSN_UID (v->insn), INSN_UID (last_giv->insn));
-                 print_rtl (loop_dump_stream, v->new_reg);
-                 putc ('\n', loop_dump_stream);
-               }
-             continue;
-           }
-         v = v->same;
-       }
-      else if (v->giv_type != DEST_REG)
-       continue;
-      if (! last_giv
-         || (last_giv->maybe_dead && ! last_giv->combined_with)
-         || ! v->maybe_dead
-         || v->combined_with)
-       last_giv = v;
-    }
-
-  ends_need_computing = 0;
-  /* For each DEST_REG giv, compute lifetime starts, and try to compute
-     lifetime ends from regscan info.  */
-  for (i = giv_count - 1; i >= 0; i--)
-    {
-      v = giv_array[stats[i].giv_number];
-      if (v->ignore)
+         && (single_use = regs->array[REGNO (g1->dest_reg)].single_usage)
+         && single_use != const0_rtx)
        continue;
-      if (v->giv_type == DEST_ADDR)
-       {
-         /* Loop unrolling of an inner loop can even create new DEST_REG
-            givs.  */
-         rtx p;
-         for (p = v->insn; INSN_UID (p) >= max_uid_for_loop;)
-           p = PREV_INSN (p);
-         stats[i].start_luid = stats[i].end_luid = INSN_LUID (p);
-         if (p != v->insn)
-           stats[i].end_luid++;
-       }
-      else /* v->giv_type == DEST_REG */
+
+      this_benefit = g1->benefit;
+      /* Add an additional weight for zero addends.  */
+      if (g1->no_const_addval)
+       this_benefit += 1;
+
+      for (j = 0; j < giv_count; j++)
        {
-         if (v->last_use)
-           {
-             stats[i].start_luid = INSN_LUID (v->insn);
-             stats[i].end_luid = INSN_LUID (v->last_use);
-           }
-         else if (INSN_UID (v->insn) >= max_uid_for_loop)
-           {
-             rtx p;
-             /* This insn has been created by loop optimization on an inner
-                loop.  We don't have a proper start_luid that will match
-                when we see the first set.  But we do know that there will
-                be no use before the set, so we can set end_luid to 0 so that
-                we'll start looking for the last use right away.  */
-             for (p = PREV_INSN (v->insn); INSN_UID (p) >= max_uid_for_loop; )
-               p = PREV_INSN (p);
-             stats[i].start_luid = INSN_LUID (p);
-             stats[i].end_luid = 0;
-             ends_need_computing++;
-           }
-         else
-           {
-             int regno = REGNO (v->dest_reg);
-             int count = VARRAY_INT (n_times_set, regno) - 1;
-             rtx p = v->insn;
-
-             /* Find the first insn that sets the giv, so that we can verify
-                if this giv's lifetime wraps around the loop.  We also need
-                the luid of the first setting insn in order to detect the
-                last use properly.  */
-             while (count)
-               {
-                 p = prev_nonnote_insn (p);
-                 if (reg_set_p (v->dest_reg, p))
-                   count--;
-               }
+         rtx this_combine;
 
-             stats[i].start_luid = INSN_LUID (p);
-             if (stats[i].start_luid > uid_luid[REGNO_FIRST_UID (regno)])
-               {
-                 stats[i].end_luid = -1;
-                 ends_need_computing++;
-               }
-             else
-               {
-                 stats[i].end_luid = uid_luid[REGNO_LAST_UID (regno)];
-                 if (stats[i].end_luid > INSN_LUID (loop->end))
-                   {
-                     stats[i].end_luid = -1;
-                     ends_need_computing++;
-                   }
-               }
+         g2 = giv_array[j];
+         if (g1 != g2
+             && (this_combine = combine_givs_p (g1, g2)) != NULL_RTX)
+           {
+             can_combine[i * giv_count + j] = this_combine;
+             this_benefit += g2->benefit + extra_benefit;
            }
        }
+      stats[i].total_benefit = this_benefit;
     }
 
-  /* If the regscan information was unconclusive for one or more DEST_REG
-     givs, scan the all insn in the loop to find out lifetime ends.  */
-  if (ends_need_computing)
-    {
-      rtx biv = bl->biv->src_reg;
-      rtx p = loop->end;
+  /* Iterate, combining until we can't.  */
+restart:
+  qsort (stats, giv_count, sizeof (*stats), cmp_combine_givs_stats);
 
-      do
+  if (loop_dump_stream)
+    {
+      fprintf (loop_dump_stream, "Sorted combine statistics:\n");
+      for (k = 0; k < giv_count; k++)
        {
-         if (p == loop->start)
-           p = loop->end;
-         p = PREV_INSN (p);
-         if (! INSN_P (p))
-           continue;
-         ends_need_computing -= find_life_end (PATTERN (p), stats, p, biv);
+         g1 = giv_array[stats[k].giv_number];
+         if (!g1->combined_with && !g1->same)
+           fprintf (loop_dump_stream, " {%d, %d}",
+                    INSN_UID (giv_array[stats[k].giv_number]->insn),
+                    stats[k].total_benefit);
        }
-      while (ends_need_computing);
+      putc ('\n', loop_dump_stream);
     }
 
-  /* Set start_luid back to the last insn that sets the giv.  This allows
-     more combinations.  */
-  for (i = giv_count - 1; i >= 0; i--)
+  for (k = 0; k < giv_count; k++)
     {
-      v = giv_array[stats[i].giv_number];
-      if (v->ignore)
-       continue;
-      if (INSN_UID (v->insn) < max_uid_for_loop)
-       stats[i].start_luid = INSN_LUID (v->insn);
-    }
+      int g1_add_benefit = 0;
 
-  /* Now adjust lifetime ends by taking combined givs into account.  */
-  for (i = giv_count - 1; i >= 0; i--)
-    {
-      unsigned luid;
-      int j;
+      i = stats[k].giv_number;
+      g1 = giv_array[i];
 
-      v = giv_array[stats[i].giv_number];
-      if (v->ignore)
+      /* If it has already been combined, skip.  */
+      if (g1->combined_with || g1->same)
        continue;
-      if (v->same && ! v->same->ignore)
+
+      for (j = 0; j < giv_count; j++)
        {
-         j = v->same->ix;
-         luid = stats[i].start_luid;
-         /* Use unsigned arithmetic to model loop wrap-around.  */
-         if (luid - stats[j].start_luid
-             > (unsigned) stats[j].end_luid - stats[j].start_luid)
-           stats[j].end_luid = luid;
-       }
-    }
+         g2 = giv_array[j];
+         if (g1 != g2 && can_combine[i * giv_count + j]
+             /* If it has already been combined, skip.  */
+             && ! g2->same && ! g2->combined_with)
+           {
+             int l;
 
-  qsort (stats, giv_count, sizeof (*stats), cmp_recombine_givs_stats);
+             g2->new_reg = can_combine[i * giv_count + j];
+             g2->same = g1;
+             g1->combined_with++;
+             g1->lifetime += g2->lifetime;
 
-  /* Try to derive DEST_REG givs from previous DEST_REG givs with the
-     same mult_val and non-overlapping lifetime.  This reduces register
-     pressure.
-     Once we find a DEST_REG giv that is suitable to derive others from,
-     we set last_giv to this giv, and try to derive as many other DEST_REG
-     givs from it without joining overlapping lifetimes.  If we then
-     encounter a DEST_REG giv that we can't derive, we set rescan to the
-     index for this giv (unless rescan is already set).
-     When we are finished with the current LAST_GIV (i.e. the inner loop
-     terminates), we start again with rescan, which then becomes the new
-     LAST_GIV.  */
-  for (i = giv_count - 1; i >= 0; i = rescan)
-    {
-      int life_start = 0, life_end = 0;
+             g1_add_benefit += g2->benefit;
 
-      for (last_giv = 0, rescan = -1; i >= 0; i--)
-       {
-         rtx sum;
+             /* ??? The new final_[bg]iv_value code does a much better job
+                of finding replaceable giv's, and hence this code may no
+                longer be necessary.  */
+             if (! g2->replaceable && REG_USERVAR_P (g2->dest_reg))
+               g1_add_benefit -= copy_cost;
 
-         v = giv_array[stats[i].giv_number];
-         if (v->giv_type != DEST_REG || v->derived_from || v->same)
-           continue;
-         if (! last_giv)
-           {
-             /* Don't use a giv that's likely to be dead to derive
-                others - that would be likely to keep that giv alive.  */
-             if (! v->maybe_dead || v->combined_with)
+             /* To help optimize the next set of combinations, remove
+                this giv from the benefits of other potential mates.  */
+             for (l = 0; l < giv_count; ++l)
                {
-                 last_giv = v;
-                 life_start = stats[i].start_luid;
-                 life_end = stats[i].end_luid;
+                 int m = stats[l].giv_number;
+                 if (can_combine[m * giv_count + j])
+                   stats[l].total_benefit -= g2->benefit + extra_benefit;
                }
-             continue;
-           }
-         /* Use unsigned arithmetic to model loop wrap around.  */
-         if (((unsigned) stats[i].start_luid - life_start
-              >= (unsigned) life_end - life_start)
-             && ((unsigned) stats[i].end_luid - life_start
-                 > (unsigned) life_end - life_start)
-             /*  Check that the giv insn we're about to use for deriving
-                 precedes all uses of that giv.  Note that initializing the
-                 derived giv would defeat the purpose of reducing register
-                 pressure.
-                 ??? We could arrange to move the insn.  */
-             && ((unsigned) stats[i].end_luid - INSN_LUID (loop->start)
-                  > (unsigned) stats[i].start_luid - INSN_LUID (loop->start))
-             && rtx_equal_p (last_giv->mult_val, v->mult_val)
-             /* ??? Could handle libcalls, but would need more logic.  */
-             && ! find_reg_note (v->insn, REG_RETVAL, NULL_RTX)
-             /* We would really like to know if for any giv that v
-                is combined with, v->insn or any intervening biv increment
-                dominates that combined giv.  However, we
-                don't have this detailed control flow information.
-                N.B. since last_giv will be reduced, it is valid
-                anywhere in the loop, so we don't need to check the
-                validity of last_giv.
-                We rely here on the fact that v->always_executed implies that
-                there is no jump to someplace else in the loop before the
-                giv insn, and hence any insn that is executed before the
-                giv insn in the loop will have a lower luid.  */
-             && (v->always_executed || ! v->combined_with)
-             && (sum = express_from (last_giv, v))
-             /* Make sure we don't make the add more expensive.  ADD_COST
-                doesn't take different costs of registers and constants into
-                account, so compare the cost of the actual SET_SRCs.  */
-             && (rtx_cost (sum, SET)
-                 <= rtx_cost (SET_SRC (single_set (v->insn)), SET))
-             /* ??? unroll can't understand anything but reg + const_int
-                sums.  It would be cleaner to fix unroll.  */
-             && ((GET_CODE (sum) == PLUS
-                  && GET_CODE (XEXP (sum, 0)) == REG
-                  && GET_CODE (XEXP (sum, 1)) == CONST_INT)
-                 || ! unroll_p)
-             && validate_change (v->insn, &PATTERN (v->insn),
-                                 gen_rtx_SET (VOIDmode, v->dest_reg, sum), 0))
-           {
-             v->derived_from = last_giv;
-             life_end = stats[i].end_luid;
 
              if (loop_dump_stream)
-               {
-                 fprintf (loop_dump_stream,
-                          "giv at %d derived from %d as ",
-                          INSN_UID (v->insn), INSN_UID (last_giv->insn));
-                 print_rtl (loop_dump_stream, sum);
-                 putc ('\n', loop_dump_stream);
-               }
+               fprintf (loop_dump_stream,
+                        "giv at %d combined with giv at %d; new benefit %d + %d, lifetime %d\n",
+                        INSN_UID (g2->insn), INSN_UID (g1->insn),
+                        g1->benefit, g1_add_benefit, g1->lifetime);
+           }
+       }
+
+      /* To help optimize the next set of combinations, remove
+        this giv from the benefits of other potential mates.  */
+      if (g1->combined_with)
+       {
+         for (j = 0; j < giv_count; ++j)
+           {
+             int m = stats[j].giv_number;
+             if (can_combine[m * giv_count + i])
+               stats[j].total_benefit -= g1->benefit + extra_benefit;
            }
-         else if (rescan < 0)
-           rescan = i;
+
+         g1->benefit += g1_add_benefit;
+
+         /* We've finished with this giv, and everything it touched.
+            Restart the combination so that proper weights for the
+            rest of the givs are properly taken into account.  */
+         /* ??? Ideally we would compact the arrays at this point, so
+            as to not cover old ground.  But sanely compacting
+            can_combine is tricky.  */
+         goto restart;
        }
     }
 
   /* Clean up.  */
-  free (giv_array);
   free (stats);
+  free (can_combine);
 }
 \f
-/* EMIT code before INSERT_BEFORE to set REG = B * M + A.  */
+/* Generate sequence for REG = B * M + A.  */
 
-void
-emit_iv_add_mult (b, m, a, reg, insert_before)
+static rtx
+gen_add_mult (b, m, a, reg)
      rtx b;          /* initial value of basic induction variable */
      rtx m;          /* multiplicative constant */
      rtx a;          /* additive constant */
      rtx reg;        /* destination register */
-     rtx insert_before;
 {
   rtx seq;
   rtx result;
 
-  /* Prevent unexpected sharing of these rtx.  */
-  a = copy_rtx (a);
-  b = copy_rtx (b);
-
-  /* Increase the lifetime of any invariants moved further in code.  */
-  update_reg_last_use (a, insert_before);
-  update_reg_last_use (b, insert_before);
-  update_reg_last_use (m, insert_before);
-
   start_sequence ();
-  result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 0);
+  /* Use unsigned arithmetic.  */
+  result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 1);
   if (reg != result)
     emit_move_insn (reg, result);
   seq = gen_sequence ();
   end_sequence ();
 
-  emit_insn_before (seq, insert_before);
+  return seq;
+}
+
 
-  /* It is entirely possible that the expansion created lots of new
-     registers.  Iterate over the sequence we just created and
-     record them all.  */
+/* Update registers created in insn sequence SEQ.  */
+
+static void
+loop_regs_update (loop, seq)
+     const struct loop *loop ATTRIBUTE_UNUSED;
+     rtx seq;
+{
+  /* Update register info for alias analysis.  */
 
   if (GET_CODE (seq) == SEQUENCE)
     {
@@ -7609,9 +6893,131 @@ emit_iv_add_mult (b, m, a, reg, insert_before)
            record_base_value (REGNO (SET_DEST (set)), SET_SRC (set), 0);
        }
     }
-  else if (GET_CODE (seq) == SET
-          && GET_CODE (SET_DEST (seq)) == REG)
-    record_base_value (REGNO (SET_DEST (seq)), SET_SRC (seq), 0);
+  else 
+    {
+      rtx set = single_set (seq);
+      if (set && GET_CODE (SET_DEST (set)) == REG)
+       record_base_value (REGNO (SET_DEST (set)), SET_SRC (set), 0);
+    }
+}
+
+
+/* EMIT code before BEFORE_BB/BEFORE_INSN to set REG = B * M + A.  */
+
+void
+loop_iv_add_mult_emit_before (loop, b, m, a, reg, before_bb, before_insn)
+     const struct loop *loop;
+     rtx b;          /* initial value of basic induction variable */
+     rtx m;          /* multiplicative constant */
+     rtx a;          /* additive constant */
+     rtx reg;        /* destination register */
+     basic_block before_bb;
+     rtx before_insn;
+{
+  rtx seq;
+
+  if (! before_insn)
+    {
+      loop_iv_add_mult_hoist (loop, b, m, a, reg);
+      return;
+    }
+
+  /* Use copy_rtx to prevent unexpected sharing of these rtx.  */
+  seq = gen_add_mult (copy_rtx (b), m, copy_rtx (a), reg);
+
+  /* Increase the lifetime of any invariants moved further in code.  */
+  update_reg_last_use (a, before_insn);
+  update_reg_last_use (b, before_insn);
+  update_reg_last_use (m, before_insn);
+
+  loop_insn_emit_before (loop, before_bb, before_insn, seq);
+
+  /* It is possible that the expansion created lots of new registers.
+     Iterate over the sequence we just created and record them all.  */
+  loop_regs_update (loop, seq);
+}
+
+
+/* Emit insns in loop pre-header to set REG = B * M + A.  */
+
+void
+loop_iv_add_mult_sink (loop, b, m, a, reg)
+     const struct loop *loop;
+     rtx b;          /* initial value of basic induction variable */
+     rtx m;          /* multiplicative constant */
+     rtx a;          /* additive constant */
+     rtx reg;        /* destination register */
+{
+  rtx seq;
+
+  /* Use copy_rtx to prevent unexpected sharing of these rtx.  */
+  seq = gen_add_mult (copy_rtx (b), m, copy_rtx (a), reg);
+
+  /* Increase the lifetime of any invariants moved further in code.
+     ???? Is this really necessary?  */
+  update_reg_last_use (a, loop->sink);
+  update_reg_last_use (b, loop->sink);
+  update_reg_last_use (m, loop->sink);
+
+  loop_insn_sink (loop, seq);
+
+  /* It is possible that the expansion created lots of new registers.
+     Iterate over the sequence we just created and record them all.  */
+  loop_regs_update (loop, seq);
+}
+
+
+/* Emit insns after loop to set REG = B * M + A.  */
+
+void
+loop_iv_add_mult_hoist (loop, b, m, a, reg)
+     const struct loop *loop;
+     rtx b;          /* initial value of basic induction variable */
+     rtx m;          /* multiplicative constant */
+     rtx a;          /* additive constant */
+     rtx reg;        /* destination register */
+{
+  rtx seq;
+
+  /* Use copy_rtx to prevent unexpected sharing of these rtx.  */
+  seq = gen_add_mult (copy_rtx (b), m, copy_rtx (a), reg);
+
+  loop_insn_hoist (loop, seq);
+
+  /* It is possible that the expansion created lots of new registers.
+     Iterate over the sequence we just created and record them all.  */
+  loop_regs_update (loop, seq);
+}
+
+
+
+/* Similar to gen_add_mult, but compute cost rather than generating
+   sequence.  */
+
+static int
+iv_add_mult_cost (b, m, a, reg)
+     rtx b;          /* initial value of basic induction variable */
+     rtx m;          /* multiplicative constant */
+     rtx a;          /* additive constant */
+     rtx reg;        /* destination register */
+{
+  int cost = 0;
+  rtx last, result;
+
+  start_sequence ();
+  result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 1);
+  if (reg != result)
+    emit_move_insn (reg, result);
+  last = get_last_insn ();
+  while (last)
+    {
+      rtx t = single_set (last);
+      if (t)
+       cost += rtx_cost (SET_SRC (t), SET);
+      last = PREV_INSN (last);
+    }
+  end_sequence ();
+  return cost;
 }
 \f
 /* Test whether A * B can be computed without
@@ -7624,8 +7030,6 @@ product_cheap_p (a, b)
 {
   int i;
   rtx tmp;
-  struct obstack *old_rtl_obstack = rtl_obstack;
-  char *storage = (char *) obstack_alloc (&temp_obstack, 0);
   int win = 1;
 
   /* If only one is constant, make it B.  */
@@ -7644,9 +7048,8 @@ product_cheap_p (a, b)
      code for the multiply and see if a call or multiply, or long sequence
      of insns is generated.  */
 
-  rtl_obstack = &temp_obstack;
   start_sequence ();
-  expand_mult (GET_MODE (a), a, b, NULL_RTX, 0);
+  expand_mult (GET_MODE (a), a, b, NULL_RTX, 1);
   tmp = gen_sequence ();
   end_sequence ();
 
@@ -7681,11 +7084,6 @@ product_cheap_p (a, b)
           && GET_CODE (SET_SRC (XVECEXP (tmp, 0, 0))) == MULT)
     win = 0;
 
-  /* Free any storage we obtained in generating this multiply and restore rtl
-     allocation to its normal obstack.  */
-  obstack_free (&temp_obstack, storage);
-  rtl_obstack = old_rtl_obstack;
-
   return win;
 }
 \f
@@ -7709,6 +7107,9 @@ check_dbra_loop (loop, insn_count)
      struct loop *loop;
      int insn_count;
 {
+  struct loop_info *loop_info = LOOP_INFO (loop);
+  struct loop_regs *regs = LOOP_REGS (loop);
+  struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *bl;
   rtx reg;
   rtx jump_label;
@@ -7723,7 +7124,6 @@ check_dbra_loop (loop, insn_count)
   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.  */
@@ -7756,7 +7156,7 @@ check_dbra_loop (loop, insn_count)
     rtx jump1;
     if ((jump1 = prev_nonnote_insn (first_compare)) != loop->cont)
       if (GET_CODE (jump1) == JUMP_INSN)
-        return 0;
+       return 0;
   }
 
   /* Check all of the bivs to see if the compare uses one of them.
@@ -7764,7 +7164,7 @@ check_dbra_loop (loop, insn_count)
      it will be zero on the last iteration.  Also skip if the biv is
      used between its update and the test insn.  */
 
-  for (bl = loop_iv_list; bl; bl = bl->next)
+  for (bl = ivs->list; bl; bl = bl->next)
     {
       if (bl->biv_count == 1
          && ! bl->biv->maybe_multiple
@@ -7859,6 +7259,7 @@ check_dbra_loop (loop, insn_count)
       if (bl->giv_count == 0 && ! loop->exit_count)
        {
          rtx bivreg = regno_reg_rtx[bl->regno];
+         struct iv_class *blt;
 
          /* If there are no givs for this biv, and the only exit is the
             fall through at the end of the loop, then
@@ -7881,10 +7282,9 @@ check_dbra_loop (loop, insn_count)
                       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)
+                                regs);
+                   if (regs->multiple_uses)
                      {
                        no_use_except_counting = 0;
                        break;
@@ -7896,12 +7296,20 @@ check_dbra_loop (loop, insn_count)
                    break;
                  }
              }
+
+         /* A biv has uses besides counting if it is used to set another biv.  */
+         for (blt = ivs->list; blt; blt = blt->next)
+           if (blt->init_set && reg_mentioned_p (bivreg, SET_SRC (blt->init_set)))
+             {
+               no_use_except_counting = 0;
+               break;
+             }
        }
 
       if (no_use_except_counting)
        /* No need to worry about MEMs.  */
        ;
-      else if (num_mem_sets <= 1)
+      else if (loop_info->num_mem_sets <= 1)
        {
          for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
            if (INSN_P (p))
@@ -7913,15 +7321,15 @@ check_dbra_loop (loop, insn_count)
             This would work if the source was invariant also, however, in that
             case, the insn should have been moved out of the loop.  */
 
-         if (num_mem_sets == 1)
+         if (loop_info->num_mem_sets == 1)
            {
              struct induction *v;
 
              reversible_mem_store
-               = (! unknown_address_altered
-                  && ! unknown_constant_address_altered
+               = (! loop_info->unknown_address_altered
+                  && ! loop_info->unknown_constant_address_altered
                   && ! loop_invariant_p (loop,
-                                         XEXP (XEXP (loop_store_mems, 0),
+                                         XEXP (XEXP (loop_info->store_mems, 0),
                                                0)));
 
              /* If the store depends on a register that is set after the
@@ -7931,8 +7339,9 @@ check_dbra_loop (loop, insn_count)
                {
                  if (v->giv_type == DEST_REG
                      && reg_mentioned_p (v->dest_reg,
-                                         PATTERN (first_loop_store_insn))
-                     && loop_insn_first_p (first_loop_store_insn, v->insn))
+                                         PATTERN (loop_info->first_loop_store_insn))
+                     && loop_insn_first_p (loop_info->first_loop_store_insn,
+                                           v->insn))
                    reversible_mem_store = 0;
                }
            }
@@ -7949,12 +7358,12 @@ check_dbra_loop (loop, insn_count)
         about all these things.  */
 
       if ((num_nonfixed_reads <= 1
-          && ! loop_info->has_call
+          && ! loop_info->has_nonconst_call
           && ! loop_info->has_volatile
           && reversible_mem_store
-          && (bl->giv_count + bl->biv_count + num_mem_sets
-             + num_movables + compare_and_branch == insn_count)
-          && (bl == loop_iv_list && bl->next == 0))
+          && (bl->giv_count + bl->biv_count + loop_info->num_mem_sets
+              + LOOP_MOVABLES (loop)->num + compare_and_branch == insn_count)
+          && (bl == ivs->list && bl->next == 0))
          || no_use_except_counting)
        {
          rtx tem;
@@ -8104,7 +7513,7 @@ check_dbra_loop (loop, insn_count)
              jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 1);
              if (jump_label == pc_rtx)
                jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 2);
-             new_add_val = GEN_INT (- INTVAL (bl->biv->add_val));
+             new_add_val = GEN_INT (-INTVAL (bl->biv->add_val));
 
              /* Set start_value; if this is not a CONST_INT, we need
                 to generate a SUB.
@@ -8115,8 +7524,7 @@ check_dbra_loop (loop, insn_count)
                  && GET_CODE (comparison_value) == CONST_INT)
                {
                  start_value = GEN_INT (comparison_val - add_adjust);
-                 emit_insn_before (gen_move_insn (reg, start_value),
-                                   loop_start);
+                 loop_insn_hoist (loop, gen_move_insn (reg, start_value));
                }
              else if (GET_CODE (initial_value) == CONST_INT)
                {
@@ -8133,9 +7541,8 @@ check_dbra_loop (loop, insn_count)
                    return 0;
                  start_value
                    = gen_rtx_PLUS (mode, comparison_value, offset);
-                 emit_insn_before ((GEN_FCN (icode)
-                                    (reg, comparison_value, offset)),
-                                   loop_start);
+                 loop_insn_hoist (loop, (GEN_FCN (icode)
+                                            (reg, comparison_value, offset)));
                  if (GET_CODE (comparison) == LE)
                    final_value = gen_rtx_PLUS (mode, comparison_value,
                                                GEN_INT (add_val));
@@ -8153,9 +7560,9 @@ check_dbra_loop (loop, insn_count)
                    return 0;
                  start_value
                    = gen_rtx_MINUS (mode, comparison_value, initial_value);
-                 emit_insn_before ((GEN_FCN (icode)
-                                    (reg, comparison_value, initial_value)),
-                                   loop_start);
+                 loop_insn_hoist (loop, (GEN_FCN (icode)
+                                            (reg, comparison_value,
+                                             initial_value)));
                }
              else
                /* We could handle the other cases too, but it'll be
@@ -8169,7 +7576,7 @@ check_dbra_loop (loop, insn_count)
              tem = gen_sequence ();
              end_sequence ();
 
-             p = emit_insn_before (tem, bl->biv->insn);
+             p = loop_insn_emit_before (loop, 0, bl->biv->insn, tem);
              delete_insn (bl->biv->insn);
 
              /* Update biv info to reflect its new status.  */
@@ -8188,15 +7595,14 @@ check_dbra_loop (loop, insn_count)
 
              /* Inc LABEL_NUSES so that delete_insn will
                 not delete the label.  */
-             LABEL_NUSES (XEXP (jump_label, 0)) ++;
+             LABEL_NUSES (XEXP (jump_label, 0))++;
 
              /* Emit an insn after the end of the loop to set the biv's
                 proper exit value if it is used anywhere outside the loop.  */
              if ((REGNO_LAST_UID (bl->regno) != INSN_UID (first_compare))
                  || ! bl->init_insn
                  || REGNO_FIRST_UID (bl->regno) != INSN_UID (bl->init_insn))
-               emit_insn_after (gen_move_insn (reg, final_value),
-                                loop_end);
+               loop_insn_sink (loop, gen_move_insn (reg, final_value));
 
              /* Delete compare/branch at end of loop.  */
              delete_insn (PREV_INSN (loop_end));
@@ -8253,9 +7659,9 @@ check_dbra_loop (loop, insn_count)
                       REG_EQUAL notes should still be correct.  */
                    if (! set
                        || GET_CODE (SET_DEST (set)) != REG
-                       || (size_t) REGNO (SET_DEST (set)) >= reg_iv_type->num_elements
-                       || REG_IV_TYPE (REGNO (SET_DEST (set))) != GENERAL_INDUCT
-                       || REG_IV_INFO (REGNO (SET_DEST (set)))->src_reg != bl->biv->src_reg)
+                       || (size_t) REGNO (SET_DEST (set)) >= ivs->n_regs
+                       || REG_IV_TYPE (ivs, REGNO (SET_DEST (set))) != GENERAL_INDUCT
+                       || REG_IV_INFO (ivs, REGNO (SET_DEST (set)))->src_reg != bl->biv->src_reg)
                      for (pnote = &REG_NOTES (p); *pnote;)
                        {
                          if (REG_NOTE_KIND (*pnote) == REG_EQUAL
@@ -8306,18 +7712,18 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
      int eliminate_p;
      int threshold, insn_count;
 {
+  struct loop_ivs *ivs = LOOP_IVS (loop);
   rtx reg = bl->biv->dest_reg;
-  rtx loop_start = loop->start;
-  rtx loop_end = loop->end;
   rtx p;
 
   /* Scan all insns in the loop, stopping if we find one that uses the
      biv in a way that we cannot eliminate.  */
 
-  for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
+  for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
     {
       enum rtx_code code = GET_CODE (p);
-      rtx where = threshold >= insn_count ? loop_start : p;
+      basic_block where_bb = 0;
+      rtx where_insn = threshold >= insn_count ? 0 : p;
 
       /* If this is a libcall that sets a giv, skip ahead to its end.  */
       if (GET_RTX_CLASS (code) == 'i')
@@ -8333,9 +7739,9 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
                {
                  unsigned int regno = REGNO (SET_DEST (set));
 
-                 if (regno < max_reg_before_loop
-                     && REG_IV_TYPE (regno) == GENERAL_INDUCT
-                     && REG_IV_INFO (regno)->src_reg == bl->biv->src_reg)
+                 if (regno < ivs->n_regs
+                     && REG_IV_TYPE (ivs, regno) == GENERAL_INDUCT
+                     && REG_IV_INFO (ivs, regno)->src_reg == bl->biv->src_reg)
                    p = last;
                }
            }
@@ -8343,7 +7749,7 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
       if ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
          && reg_mentioned_p (reg, PATTERN (p))
          && ! maybe_eliminate_biv_1 (loop, PATTERN (p), p, bl,
-                                     eliminate_p, where))
+                                     eliminate_p, where_bb, where_insn))
        {
          if (loop_dump_stream)
            fprintf (loop_dump_stream,
@@ -8353,7 +7759,7 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
        }
     }
 
-  if (p == loop_end)
+  if (p == loop->end)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream, "biv %d %s eliminated.\n",
@@ -8417,22 +7823,6 @@ biv_elimination_giv_has_0_offset (biv, giv, insn)
              && loop_insn_first_p (insn, giv->insn))))
     return 0;
 
-  /* If the giv V was derived from another giv, and INSN does
-     not occur between the giv insn and the biv insn, then we'd
-     have to adjust the value used here.  This is rare, so we don't
-     bother to make this possible.  */
-  if (giv->derived_from
-      && ! (giv->always_executed
-           && loop_insn_first_p (giv->insn, insn)
-           && loop_insn_first_p (insn, biv->insn)))
-    return 0;
-  if (giv->same
-      && giv->same->derived_from
-      && ! (giv->same->always_executed
-           && loop_insn_first_p (giv->same->insn, insn)
-           && loop_insn_first_p (insn, biv->insn)))
-    return 0;
-
   return 1;
 }
 
@@ -8441,18 +7831,20 @@ biv_elimination_giv_has_0_offset (biv, giv, insn)
 
    If BIV does not appear in X, return 1.
 
-   If ELIMINATE_P is non-zero, actually do the elimination.  WHERE indicates
-   where extra insns should be added.  Depending on how many items have been
-   moved out of the loop, it will either be before INSN or at the start of
-   the loop.  */
+   If ELIMINATE_P is non-zero, actually do the elimination.
+   WHERE_INSN/WHERE_BB indicate where extra insns should be added.
+   Depending on how many items have been moved out of the loop, it
+   will either be before INSN (when WHERE_INSN is non-zero) or at the
+   start of the loop (when WHERE_INSN is zero).  */
 
 static int
-maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
+maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn)
      const struct loop *loop;
      rtx x, insn;
      struct iv_class *bl;
      int eliminate_p;
-     rtx where;
+     basic_block where_bb;
+     rtx where_insn;
 {
   enum rtx_code code = GET_CODE (x);
   rtx reg = bl->biv->dest_reg;
@@ -8536,7 +7928,7 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                    || GET_CODE (v->add_val) == LABEL_REF
                    || GET_CODE (v->add_val) == CONST
                    || (GET_CODE (v->add_val) == REG
-                       && REGNO_POINTER_FLAG (REGNO (v->add_val)))))
+                       && REG_POINTER (v->add_val))))
              {
                if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
                  continue;
@@ -8562,8 +7954,9 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                   into a register (it will be a loop invariant.)  */
                tem = gen_reg_rtx (GET_MODE (v->new_reg));
 
-               emit_insn_before (gen_move_insn (tem, copy_rtx (v->add_val)),
-                                 where);
+               loop_insn_emit_before (loop, 0, where_insn,
+                                      gen_move_insn (tem,
+                                                     copy_rtx (v->add_val)));
 
                /* Substitute the new register for its invariant value in
                   the compare expression.  */
@@ -8600,7 +7993,7 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                    || GET_CODE (v->add_val) == LABEL_REF
                    || GET_CODE (v->add_val) == CONST
                    || (GET_CODE (v->add_val) == REG
-                       && REGNO_POINTER_FLAG (REGNO (v->add_val))))
+                       && REG_POINTER (v->add_val)))
                && ! v->ignore && ! v->maybe_dead && v->always_computable
                && v->mode == mode)
              {
@@ -8629,7 +8022,9 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                  {
                    /* Otherwise, load it into a register.  */
                    tem = gen_reg_rtx (mode);
-                   emit_iv_add_mult (arg, v->mult_val, v->add_val, tem, where);
+                   loop_iv_add_mult_emit_before (loop, arg,
+                                                 v->mult_val, v->add_val,
+                                                 tem, where_bb, where_insn);
                    validate_change (insn, &XEXP (x, arg_operand), tem, 1);
                  }
                if (apply_change_group ())
@@ -8662,7 +8057,9 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                                 v->new_reg, 1);
 
                /* Compute value to compare against.  */
-               emit_iv_add_mult (arg, v->mult_val, v->add_val, tem, where);
+               loop_iv_add_mult_emit_before (loop, arg, 
+                                             v->mult_val, v->add_val,
+                                             tem, where_bb, where_insn);
                /* Use it in this insn.  */
                validate_change (insn, &XEXP (x, arg_operand), tem, 1);
                if (apply_change_group ())
@@ -8698,8 +8095,9 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
                                     v->new_reg, 1);
 
                    /* Compute value to compare against.  */
-                   emit_iv_add_mult (arg, v->mult_val, v->add_val,
-                                     tem, where);
+                   loop_iv_add_mult_emit_before (loop, arg, 
+                                                 v->mult_val, v->add_val,
+                                                 tem, where_bb, where_insn);
                    validate_change (insn, &XEXP (x, arg_operand), tem, 1);
                    if (apply_change_group ())
                      return 1;
@@ -8721,7 +8119,7 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
 #if 0
          /* Otherwise the reg compared with had better be a biv.  */
          if (GET_CODE (arg) != REG
-             || REG_IV_TYPE (REGNO (arg)) != BASIC_INDUCT)
+             || REG_IV_TYPE (ivs, REGNO (arg)) != BASIC_INDUCT)
            return 0;
 
          /* Look for a pair of givs, one for each biv,
@@ -8733,7 +8131,8 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
              if (v->ignore || v->maybe_dead || v->mode != mode)
                continue;
 
-             for (tv = reg_biv_class[REGNO (arg)]->giv; tv; tv = tv->next_iv)
+             for (tv = REG_IV_CLASS (ivs, REGNO (arg))->giv; tv; 
+                  tv = tv->next_iv)
                if (! tv->ignore && ! tv->maybe_dead
                    && rtx_equal_p (tv->mult_val, v->mult_val)
                    && rtx_equal_p (tv->add_val, v->add_val)
@@ -8779,14 +8178,14 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
        {
        case 'e':
          if (! maybe_eliminate_biv_1 (loop, XEXP (x, i), insn, bl,
-                                      eliminate_p, where))
+                                      eliminate_p, where_bb, where_insn))
            return 0;
          break;
 
        case 'E':
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            if (! maybe_eliminate_biv_1 (loop, XVECEXP (x, i, j), insn, bl,
-                                        eliminate_p, where))
+                                        eliminate_p, where_bb, where_insn))
              return 0;
          break;
        }
@@ -8823,14 +8222,15 @@ record_initial (dest, set, data)
      rtx set;
      void *data ATTRIBUTE_UNUSED;
 {
+  struct loop_ivs *ivs = (struct loop_ivs *) data;
   struct iv_class *bl;
 
   if (GET_CODE (dest) != REG
-      || REGNO (dest) >= max_reg_before_loop
-      || REG_IV_TYPE (REGNO (dest)) != BASIC_INDUCT)
+      || REGNO (dest) >= ivs->n_regs
+      || REG_IV_TYPE (ivs, REGNO (dest)) != BASIC_INDUCT)
     return;
 
-  bl = reg_biv_class[REGNO (dest)];
+  bl = REG_IV_CLASS (ivs, REGNO (dest));
 
   /* If this is the first set found, record it.  */
   if (bl->init_insn == 0)
@@ -8843,7 +8243,7 @@ record_initial (dest, set, data)
 /* If any of the registers in X are "old" and currently have a last use earlier
    than INSN, update them to have a last use of INSN.  Their actual last use
    will be the previous insn but it will not have a valid uid_luid so we can't
-   use it.  */
+   use it.  X must be a source expression only.  */
 
 static void
 update_reg_last_use (x, insn)
@@ -8853,11 +8253,15 @@ update_reg_last_use (x, insn)
   /* Check for the case where INSN does not have a valid luid.  In this case,
      there is no need to modify the regno_last_uid, as this can only happen
      when code is inserted after the loop_end to set a pseudo's final value,
-     and hence this insn will never be the last use of x.  */
+     and hence this insn will never be the last use of x. 
+     ???? This comment is not correct.  See for example loop_givs_reduce.  
+     This may insert an insn before another new insn.  */
   if (GET_CODE (x) == REG && REGNO (x) < max_reg_before_loop
       && INSN_UID (insn) < max_uid_for_loop
-      && uid_luid[REGNO_LAST_UID (REGNO (x))] < uid_luid[INSN_UID (insn)])
-    REGNO_LAST_UID (REGNO (x)) = INSN_UID (insn);
+      && REGNO_LAST_LUID (REGNO (x)) < INSN_LUID (insn))
+    {
+      REGNO_LAST_UID (REGNO (x)) = INSN_UID (insn);
+    }
   else
     {
       register int i, j;
@@ -8910,7 +8314,6 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
   rtx tem;
   rtx op0, op1;
   int reverse_code = 0;
-  int did_reverse_condition = 0;
   enum machine_mode mode;
 
   code = GET_CODE (cond);
@@ -8919,10 +8322,9 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
   op1 = XEXP (cond, 1);
 
   if (reverse)
-    {
-      code = reverse_condition (code);
-      did_reverse_condition ^= 1;
-    }
+    code = reversed_comparison_code (cond, insn);
+  if (code == UNKNOWN)
+    return 0;
 
   if (earliest)
     *earliest = insn;
@@ -8933,7 +8335,7 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
      in cse.c  */
 
   while (GET_RTX_CLASS (code) == '<'
-         && op1 == CONST0_RTX (GET_MODE (op0))
+        && op1 == CONST0_RTX (GET_MODE (op0))
         && op0 != want_reg)
     {
       /* Set non-zero when we find something of interest.  */
@@ -8973,13 +8375,19 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
 
       if ((prev = prev_nonnote_insn (prev)) == 0
          || GET_CODE (prev) != INSN
-         || FIND_REG_INC_NOTE (prev, 0)
-         || (set = single_set (prev)) == 0)
+         || FIND_REG_INC_NOTE (prev, 0))
+       break;
+
+      set = set_of (op0, prev);
+
+      if (set
+         && (GET_CODE (set) != SET
+             || !rtx_equal_p (SET_DEST (set), op0)))
        break;
 
       /* If this is setting OP0, get what it sets it to if it looks
         relevant.  */
-      if (rtx_equal_p (SET_DEST (set), op0))
+      if (set)
        {
          enum machine_mode inner_mode = GET_MODE (SET_DEST (set));
 
@@ -9039,10 +8447,6 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
                       || mode == VOIDmode || inner_mode == VOIDmode))
 
            {
-             /* We might have reversed a LT to get a GE here.  But this wasn't
-                actually the comparison of data, so we don't flag that we
-                have had to reverse the condition.  */
-             did_reverse_condition ^= 1;
              reverse_code = 1;
              x = SET_SRC (set);
            }
@@ -9060,10 +8464,9 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
            code = GET_CODE (x);
          if (reverse_code)
            {
-             code = reverse_condition (code);
+             code = reversed_comparison_code (x, prev);
              if (code == UNKNOWN)
                return 0;
-             did_reverse_condition ^= 1;
              reverse_code = 0;
            }
 
@@ -9126,15 +8529,6 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
        }
     }
 
-  /* If this was floating-point and we reversed anything other than an
-     EQ or NE or (UN)ORDERED, return zero.  */
-  if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-      && did_reverse_condition
-      && code != NE && code != EQ && code != UNORDERED && code != ORDERED
-      && ! flag_fast_math
-      && GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
-    return 0;
-
 #ifdef HAVE_cc0
   /* Never return CC0; return zero instead.  */
   if (op0 == cc0_rtx)
@@ -9225,6 +8619,7 @@ insert_loop_mem (mem, data)
      rtx *mem;
      void *data ATTRIBUTE_UNUSED;
 {
+  struct loop_info *loop_info = data;
   int i;
   rtx m = *mem;
 
@@ -9255,137 +8650,186 @@ insert_loop_mem (mem, data)
     }
 
   /* See if we've already seen this MEM.  */
-  for (i = 0; i < loop_mems_idx; ++i)
-    if (rtx_equal_p (m, loop_mems[i].mem))
+  for (i = 0; i < loop_info->mems_idx; ++i)
+    if (rtx_equal_p (m, loop_info->mems[i].mem))
       {
-       if (GET_MODE (m) != GET_MODE (loop_mems[i].mem))
+       if (GET_MODE (m) != GET_MODE (loop_info->mems[i].mem))
          /* The modes of the two memory accesses are different.  If
             this happens, something tricky is going on, and we just
             don't optimize accesses to this MEM.  */
-         loop_mems[i].optimize = 0;
+         loop_info->mems[i].optimize = 0;
 
        return 0;
       }
 
   /* Resize the array, if necessary.  */
-  if (loop_mems_idx == loop_mems_allocated)
+  if (loop_info->mems_idx == loop_info->mems_allocated)
     {
-      if (loop_mems_allocated != 0)
-       loop_mems_allocated *= 2;
+      if (loop_info->mems_allocated != 0)
+       loop_info->mems_allocated *= 2;
       else
-       loop_mems_allocated = 32;
+       loop_info->mems_allocated = 32;
 
-      loop_mems = (loop_mem_info*)
-       xrealloc (loop_mems,
-                 loop_mems_allocated * sizeof (loop_mem_info));
+      loop_info->mems = (loop_mem_info *)
+       xrealloc (loop_info->mems,
+                 loop_info->mems_allocated * sizeof (loop_mem_info));
     }
 
   /* Actually insert the MEM.  */
-  loop_mems[loop_mems_idx].mem = m;
+  loop_info->mems[loop_info->mems_idx].mem = m;
   /* We can't hoist this MEM out of the loop if it's a BLKmode MEM
      because we can't put it in a register.  We still store it in the
      table, though, so that if we see the same address later, but in a
      non-BLK mode, we'll not think we can optimize it at that point.  */
-  loop_mems[loop_mems_idx].optimize = (GET_MODE (m) != BLKmode);
-  loop_mems[loop_mems_idx].reg = NULL_RTX;
-  ++loop_mems_idx;
+  loop_info->mems[loop_info->mems_idx].optimize = (GET_MODE (m) != BLKmode);
+  loop_info->mems[loop_info->mems_idx].reg = NULL_RTX;
+  ++loop_info->mems_idx;
 
   return 0;
 }
 
-/* Like load_mems, but also ensures that SET_IN_LOOP,
-   MAY_NOT_OPTIMIZE, REG_SINGLE_USAGE, and INSN_COUNT have the correct
-   values after load_mems.  */
+
+/* Allocate REGS->ARRAY or reallocate it if it is too small.
+
+   Increment REGS->ARRAY[I].SET_IN_LOOP at the index I of each
+   register that is modified by an insn between FROM and TO.  If the
+   value of an element of REGS->array[I].SET_IN_LOOP becomes 127 or
+   more, stop incrementing it, to avoid overflow.
+
+   Store in REGS->ARRAY[I].SINGLE_USAGE the single insn in which
+   register I is used, if it is only used once.  Otherwise, it is set
+   to 0 (for no uses) or const0_rtx for more than one use.  This
+   parameter may be zero, in which case this processing is not done.
+
+   Set REGS->ARRAY[I].MAY_NOT_OPTIMIZE nonzero if we should not
+   optimize register I.
+
+   Store in *COUNT_PTR the number of actual instructions
+   in the loop.  We use this to decide what is worth moving out.  */
 
 static void
-load_mems_and_recount_loop_regs_set (loop, insn_count)
+loop_regs_scan (loop, extra_size, count_ptr)
      const struct loop *loop;
-     int *insn_count;
+     int extra_size;
+     int *count_ptr;
 {
-  int nregs = max_reg_num ();
+  struct loop_regs *regs = LOOP_REGS (loop);
+  int old_nregs;
+  /* last_set[n] is nonzero iff reg n has been set in the current
+   basic block.  In that case, it is the insn that last set reg n.  */
+  rtx *last_set;
+  rtx insn;
+  int count = 0;
+  int i;
 
-  load_mems (loop);
+  old_nregs = regs->num;
+  regs->num = max_reg_num ();
 
-  /* Recalculate set_in_loop and friends since load_mems may have
-     created new registers.  */
-  if (max_reg_num () > nregs)
+  /* Grow the regs array if not allocated or too small.  */
+  if (regs->num >= regs->size)
     {
-      int i;
-      int old_nregs;
+      regs->size = regs->num + extra_size;
+      
+      regs->array = (struct loop_reg *)
+       xrealloc (regs->array, regs->size * sizeof (*regs->array));
+
+      /* Zero the new elements.  */
+      memset (regs->array + old_nregs, 0,
+             (regs->size - old_nregs) * sizeof (*regs->array));
+    }
+
+  /* Clear previously scanned fields but do not clear n_times_set.  */
+  for (i = 0; i < old_nregs; i++)
+    {
+      regs->array[i].set_in_loop = 0;
+      regs->array[i].may_not_optimize = 0;
+      regs->array[i].single_usage = NULL_RTX;
+    }
+
+  last_set = (rtx *) xcalloc (regs->num, sizeof (rtx));
+
+  /* Scan the loop, recording register usage.  */
+  for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
+       insn = NEXT_INSN (insn))
+    {
+      if (INSN_P (insn))
+       {
+         ++count;
 
-      old_nregs = nregs;
-      nregs = max_reg_num ();
+         /* Record registers that have exactly one use.  */
+         find_single_use_in_loop (regs, insn, PATTERN (insn));
 
-      if ((unsigned) nregs > set_in_loop->num_elements)
-       {
-         /* Grow all the arrays.  */
-         VARRAY_GROW (set_in_loop, nregs);
-         VARRAY_GROW (n_times_set, nregs);
-         VARRAY_GROW (may_not_optimize, nregs);
-         VARRAY_GROW (reg_single_usage, nregs);
+         /* Include uses in REG_EQUAL notes.  */
+         if (REG_NOTES (insn))
+           find_single_use_in_loop (regs, insn, REG_NOTES (insn));
+
+         if (GET_CODE (PATTERN (insn)) == SET
+             || GET_CODE (PATTERN (insn)) == CLOBBER)
+           count_one_set (regs, insn, PATTERN (insn), last_set);
+         else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+           {
+             register int i;
+             for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+               count_one_set (regs, insn, XVECEXP (PATTERN (insn), 0, i),
+                              last_set);
+           }
        }
-      /* Clear the arrays */
-      bzero ((char *) &set_in_loop->data, nregs * sizeof (int));
-      bzero ((char *) &may_not_optimize->data, nregs * sizeof (char));
-      bzero ((char *) &reg_single_usage->data, nregs * sizeof (rtx));
 
-      count_loop_regs_set (loop, may_not_optimize, reg_single_usage,
-                          insn_count, nregs);
+      if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
+       memset (last_set, 0, regs->num * sizeof (rtx));
+    }
 
-      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-       {
-         VARRAY_CHAR (may_not_optimize, i) = 1;
-         VARRAY_INT (set_in_loop, i) = 1;
-       }
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      regs->array[i].may_not_optimize = 1;
+      regs->array[i].set_in_loop = 1;
+    }
 
 #ifdef AVOID_CCMODE_COPIES
-      /* Don't try to move insns which set CC registers if we should not
-        create CCmode register copies.  */
-      for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
-       if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
-         VARRAY_CHAR (may_not_optimize, i) = 1;
+  /* Don't try to move insns which set CC registers if we should not
+     create CCmode register copies.  */
+  for (i = regs->num - 1; i >= FIRST_PSEUDO_REGISTER; i--)
+    if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
+      regs->array[i].may_not_optimize = 1;
 #endif
+  
+  /* Set regs->array[I].n_times_set for the new registers.  */
+  for (i = old_nregs; i < regs->num; i++)
+    regs->array[i].n_times_set = regs->array[i].set_in_loop;
 
-      /* Set n_times_set for the new registers.  */
-      bcopy ((char *) (&set_in_loop->data.i[0] + old_nregs),
-            (char *) (&n_times_set->data.i[0] + old_nregs),
-            (nregs - old_nregs) * sizeof (int));
-    }
+  free (last_set);
+  *count_ptr = count;
 }
 
+
 /* Move MEMs into registers for the duration of the loop.  */
 
 static void
 load_mems (loop)
      const struct loop *loop;
 {
+  struct loop_info *loop_info = LOOP_INFO (loop);
+  struct loop_regs *regs = LOOP_REGS (loop);
   int maybe_never = 0;
   int i;
   rtx p;
   rtx label = NULL_RTX;
-  rtx end_label = NULL_RTX;
+  rtx end_label;
   /* Nonzero if the next instruction may never be executed.  */
   int next_maybe_never = 0;
-  int last_max_reg = max_reg_num ();
+  unsigned int last_max_reg = max_reg_num ();
 
-  if (loop_mems_idx == 0)
+  if (loop_info->mems_idx == 0)
     return;
 
-  /* Find start of the extended basic block that enters the loop.  */
-  for (p = loop->start;
-       PREV_INSN (p) && GET_CODE (p) != CODE_LABEL;
-       p = PREV_INSN (p))
-    ;
-
-  cselib_init ();
-
-  /* Build table of mems that get set to constant values before the
-     loop.  */
-  for (; p != loop->start; p = NEXT_INSN (p))
-    cselib_process_insn (p);
+  /* We cannot use next_label here because it skips over normal insns.  */
+  end_label = next_nonnote_insn (loop->end);
+  if (end_label && GET_CODE (end_label) != CODE_LABEL)
+    end_label = NULL_RTX;
 
-  /* Check to see if it's possible that some instructions in the
-     loop are never executed.  */
+  /* Check to see if it's possible that some instructions in the loop are
+     never executed.  Also check if there is a goto out of the loop other
+     than right after the end of the loop.  */
   for (p = next_insn_in_loop (loop, loop->scan_start);
        p != NULL_RTX && ! maybe_never;
        p = next_insn_in_loop (loop, p))
@@ -9404,6 +8848,15 @@ load_mems (loop)
                     && NEXT_INSN (NEXT_INSN (p)) == loop->end
                     && any_uncondjump_p (p)))
        {
+         /* If this is a jump outside of the loop but not right
+            after the end of the loop, we would have to emit new fixup
+            sequences for each such label.  */
+         if (JUMP_LABEL (p) != end_label
+             && (INSN_UID (JUMP_LABEL (p)) >= max_uid_for_loop
+                 || INSN_LUID (JUMP_LABEL (p)) < INSN_LUID (loop->start)
+                 || INSN_LUID (JUMP_LABEL (p)) > INSN_LUID (loop->end)))
+           return;
+
          if (!any_condjump_p (p))
            /* Something complicated.  */
            maybe_never = 1;
@@ -9416,24 +8869,37 @@ load_mems (loop)
        maybe_never = 1;
     }
 
+  /* Find start of the extended basic block that enters the loop.  */
+  for (p = loop->start;
+       PREV_INSN (p) && GET_CODE (p) != CODE_LABEL;
+       p = PREV_INSN (p))
+    ;
+
+  cselib_init ();
+
+  /* Build table of mems that get set to constant values before the
+     loop.  */
+  for (; p != loop->start; p = NEXT_INSN (p))
+    cselib_process_insn (p);
+
   /* Actually move the MEMs.  */
-  for (i = 0; i < loop_mems_idx; ++i)
+  for (i = 0; i < loop_info->mems_idx; ++i)
     {
       regset_head load_copies;
       regset_head store_copies;
       int written = 0;
       rtx reg;
-      rtx mem = loop_mems[i].mem;
+      rtx mem = loop_info->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;
+       loop_info->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;
+      mem_list_entry = loop_info->store_mems;
       while (mem_list_entry)
        {
          if (rtx_equal_p (mem, XEXP (mem_list_entry, 0)))
@@ -9442,7 +8908,7 @@ load_mems (loop)
                                    mem, rtx_varies_p))
            {
              /* MEM is indeed aliased by this store.  */
-             loop_mems[i].optimize = 0;
+             loop_info->mems[i].optimize = 0;
              break;
            }
          mem_list_entry = XEXP (mem_list_entry, 1);
@@ -9450,27 +8916,27 @@ load_mems (loop)
 
       if (flag_float_store && written
          && GET_MODE_CLASS (GET_MODE (mem)) == MODE_FLOAT)
-       loop_mems[i].optimize = 0;
+       loop_info->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)
+      if (loop_info->mems[i].optimize && written)
        {
          int j;
 
-         for (j = 0; j < loop_mems_idx; ++j)
+         for (j = 0; j < loop_info->mems_idx; ++j)
            {
              if (j == i)
                continue;
              else if (true_dependence (mem,
                                        VOIDmode,
-                                       loop_mems[j].mem,
+                                       loop_info->mems[j].mem,
                                        rtx_varies_p))
                {
-                 /* It's not safe to hoist loop_mems[i] out of
+                 /* It's not safe to hoist loop_info->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;
+                    seen by reads from loop_info->mems[j].  */
+                 loop_info->mems[i].optimize = 0;
                  break;
                }
            }
@@ -9479,9 +8945,9 @@ load_mems (loop)
       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;
+       loop_info->mems[i].optimize = 0;
 
-      if (!loop_mems[i].optimize)
+      if (!loop_info->mems[i].optimize)
        /* We thought we were going to lift this MEM out of the
           loop, but later discovered that we could not.  */
        continue;
@@ -9495,7 +8961,7 @@ load_mems (loop)
         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;
+      loop_info->mems[i].reg = reg;
 
       /* Now, replace all references to the MEM with the
         corresponding pesudos.  */
@@ -9504,8 +8970,6 @@ load_mems (loop)
           p != NULL_RTX;
           p = next_insn_in_loop (loop, p))
        {
-         rtx_and_int ri;
-
          if (INSN_P (p))
            {
              rtx set;
@@ -9521,28 +8985,27 @@ load_mems (loop)
                  && GET_CODE (SET_DEST (set)) == REG
                  && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
                  && REGNO (SET_DEST (set)) < last_max_reg
-                 && VARRAY_INT (n_times_set, REGNO (SET_DEST (set))) == 1
+                 && regs->array[REGNO (SET_DEST (set))].n_times_set == 1
                  && rtx_equal_p (SET_SRC (set), mem))
                SET_REGNO_REG_SET (&load_copies, REGNO (SET_DEST (set)));
 
-             /* See if this copies the mem from a register that isn't
+             /* See if this copies the mem from a register that isn't
                 modified afterwards.  We'll try to remove the
                 redundant copy later on by doing a little register
                 renaming and copy propagation.   This will help
                 to untangle things for the BIV detection code.  */
-             if (set
-                 && ! maybe_never
-                 && GET_CODE (SET_SRC (set)) == REG
-                 && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER
-                 && REGNO (SET_SRC (set)) < last_max_reg
-                 && VARRAY_INT (n_times_set, REGNO (SET_SRC (set))) == 1
-                 && rtx_equal_p (SET_DEST (set), mem))
-               SET_REGNO_REG_SET (&store_copies, REGNO (SET_SRC (set)));
-             
-             /* Replace the memory reference with the shadow register.  */
-             ri.r = p;
-             ri.i = i;
-             for_each_rtx (&p, replace_loop_mem, &ri);
+             if (set
+                 && ! maybe_never
+                 && GET_CODE (SET_SRC (set)) == REG
+                 && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER
+                 && REGNO (SET_SRC (set)) < last_max_reg
+                 && regs->array[REGNO (SET_SRC (set))].n_times_set == 1
+                 && rtx_equal_p (SET_DEST (set), mem))
+               SET_REGNO_REG_SET (&store_copies, REGNO (SET_SRC (set)));
+
+             /* Replace the memory reference with the shadow register.  */
+             replace_loop_mems (p, loop_info->mems[i].mem,
+                                loop_info->mems[i].reg);
            }
 
          if (GET_CODE (p) == CODE_LABEL
@@ -9552,7 +9015,7 @@ load_mems (loop)
 
       if (! apply_change_group ())
        /* We couldn't replace all occurrences of the MEM.  */
-       loop_mems[i].optimize = 0;
+       loop_info->mems[i].optimize = 0;
       else
        {
          /* Load the memory immediately before LOOP->START, which is
@@ -9599,7 +9062,7 @@ load_mems (loop)
                best = copy_rtx (best_equiv->loc);
            }
          set = gen_move_insn (reg, best);
-         set = emit_insn_before (set, loop->start);
+         set = loop_insn_hoist (loop, set);
          if (const_equiv)
            REG_NOTES (set) = gen_rtx_EXPR_LIST (REG_EQUAL,
                                                 copy_rtx (const_equiv->loc),
@@ -9609,10 +9072,6 @@ load_mems (loop)
            {
              if (label == NULL_RTX)
                {
-                 /* We must compute the former
-                    right-after-the-end label before we insert
-                    the new one.  */
-                 end_label = next_label (loop->end);
                  label = gen_label_rtx ();
                  emit_label_after (label, loop->end);
                }
@@ -9620,7 +9079,7 @@ load_mems (loop)
              /* Store the memory immediately after END, which is
                 the NOTE_LOOP_END.  */
              set = gen_move_insn (copy_rtx (mem), reg);
-             emit_insn_after (set, label);
+             loop_insn_emit_after (loop, 0, label, set);
            }
 
          if (loop_dump_stream)
@@ -9650,7 +9109,7 @@ load_mems (loop)
        }
     }
 
-  if (label != NULL_RTX)
+  if (label != NULL_RTX && end_label != NULL_RTX)
     {
       /* Now, we need to replace all references to the previous exit
         label with the new one.  */
@@ -9746,12 +9205,8 @@ try_copy_prop (loop, replacement, regno)
       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);
+         replace_loop_regs (insn, reg_rtx, replacement);
          if (REGNO_LAST_UID (regno) == INSN_UID (insn))
            replaced_last = 1;
 
@@ -9782,7 +9237,6 @@ try_copy_prop (loop, replacement, regno)
     }
 }
 
-
 /* Try to replace occurrences of pseudo REGNO with REPLACEMENT within
    loop LOOP if the order of the sets of these registers can be
    swapped.  There must be exactly one insn within the loop that sets
@@ -9795,7 +9249,7 @@ try_swap_copy_prop (loop, replacement, regno)
      unsigned int regno;
 {
   rtx insn;
-  rtx set;
+  rtx set = NULL_RTX;
   unsigned int new_regno;
 
   new_regno = REGNO (replacement);
@@ -9805,7 +9259,7 @@ try_swap_copy_prop (loop, replacement, regno)
        insn = next_insn_in_loop (loop, insn))
     {
       /* Search for the insn that copies REGNO to NEW_REGNO?  */
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+      if (INSN_P (insn)
          && (set = single_set (insn))
          && GET_CODE (SET_DEST (set)) == REG
          && REGNO (SET_DEST (set)) == new_regno
@@ -9814,18 +9268,18 @@ try_swap_copy_prop (loop, replacement, regno)
        break;
     }
 
-  if (insn != NULL_RTX)
+  if (set)
     {
       rtx prev_insn;
       rtx prev_set;
-      
+
       /* Some DEF-USE info would come in handy here to make this
         function more general.  For now, just check the previous insn
         which is the most likely candidate for setting REGNO.  */
-      
+
       prev_insn = PREV_INSN (insn);
-      
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+
+      if (INSN_P (insn)
          && (prev_set = single_set (prev_insn))
          && GET_CODE (SET_DEST (prev_set)) == REG
          && REGNO (SET_DEST (prev_set)) == regno)
@@ -9833,7 +9287,7 @@ try_swap_copy_prop (loop, replacement, regno)
          /* We have:
             (set (reg regno) (expr))
             (set (reg new_regno) (reg regno))
-            
+
             so try converting this to:
             (set (reg new_regno) (expr))
             (set (reg regno) (reg new_regno))
@@ -9853,9 +9307,9 @@ try_swap_copy_prop (loop, replacement, regno)
          if (apply_change_group ())
            {
              if (loop_dump_stream)
-               fprintf (loop_dump_stream, 
-                        "  Swapped set of reg %d at %d with reg %d at %d.\n", 
-                        regno, INSN_UID (insn), 
+               fprintf (loop_dump_stream,
+                        "  Swapped set of reg %d at %d with reg %d at %d.\n",
+                        regno, INSN_UID (insn),
                         new_regno, INSN_UID (prev_insn));
 
              /* Update first use of REGNO.  */
@@ -9870,10 +9324,9 @@ try_swap_copy_prop (loop, replacement, regno)
     }
 }
 
-
 /* Replace MEM with its associated pseudo register.  This function is
-   called from load_mems via for_each_rtx.  DATA is actually an
-   rtx_and_int * describing the instruction currently being scanned
+   called from load_mems via for_each_rtx.  DATA is actually a pointer
+   to a structure describing the instruction currently being scanned
    and the MEM we are currently replacing.  */
 
 static int
@@ -9881,9 +9334,7 @@ replace_loop_mem (mem, data)
      rtx *mem;
      void *data;
 {
-  rtx_and_int *ri;
-  rtx insn;
-  int i;
+  loop_replace_args *args = (loop_replace_args *) data;
   rtx m = *mem;
 
   if (m == NULL_RTX)
@@ -9904,25 +9355,34 @@ replace_loop_mem (mem, data)
       return 0;
     }
 
-  ri = (rtx_and_int *) data;
-  i = ri->i;
-
-  if (!rtx_equal_p (loop_mems[i].mem, m))
+  if (!rtx_equal_p (args->match, m))
     /* This is not the MEM we are currently replacing.  */
     return 0;
 
-  insn = ri->r;
-
   /* Actually replace the MEM.  */
-  validate_change (insn, mem, loop_mems[i].reg, 1);
+  validate_change (args->insn, mem, args->replacement, 1);
 
   return 0;
 }
 
+static void
+replace_loop_mems (insn, mem, reg)
+     rtx insn;
+     rtx mem;
+     rtx reg;
+{
+  loop_replace_args args;
+
+  args.insn = insn;
+  args.match = mem;
+  args.replacement = reg;
+
+  for_each_rtx (&insn, replace_loop_mem, &args);
+}
+
 /* 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.  */
+   to the rtx being scanned.  DATA is actually a pointer to
+   a structure of arguments.  */
 
 static int
 replace_loop_reg (px, data)
@@ -9930,17 +9390,32 @@ replace_loop_reg (px, data)
      void *data;
 {
   rtx x = *px;
-  rtx *array = (rtx *) data;
+  loop_replace_args *args = (loop_replace_args *) data;
 
   if (x == NULL_RTX)
     return 0;
 
-  if (x == array[0])
-    validate_change (array[2], px, array[1], 1);
+  if (x == args->match)
+    validate_change (args->insn, px, args->replacement, 1);
 
   return 0;
 }
 
+static void
+replace_loop_regs (insn, reg, replacement)
+     rtx insn;
+     rtx reg;
+     rtx replacement;
+{
+  loop_replace_args args;
+
+  args.insn = insn;
+  args.match = reg;
+  args.replacement = replacement;
+
+  for_each_rtx (&insn, replace_loop_reg, &args);
+}
+
 /* 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.  */
@@ -9970,6 +9445,312 @@ replace_label (x, data)
   return 0;
 }
 \f
+/* Emit insn for PATTERN after WHERE_INSN in basic block WHERE_BB
+   (ignored in the interim).  */
+
+static rtx
+loop_insn_emit_after (loop, where_bb, where_insn, pattern)
+     const struct loop *loop ATTRIBUTE_UNUSED;
+     basic_block where_bb ATTRIBUTE_UNUSED;
+     rtx where_insn;
+     rtx pattern;
+{
+  return emit_insn_after (pattern, where_insn);
+}
+
+
+/* If WHERE_INSN is non-zero emit insn for PATTERN before WHERE_INSN
+   in basic block WHERE_BB (ignored in the interim) within the loop
+   otherwise hoist PATTERN into the loop pre-header.  */
+
+rtx
+loop_insn_emit_before (loop, where_bb, where_insn, pattern)
+     const struct loop *loop;
+     basic_block where_bb ATTRIBUTE_UNUSED;
+     rtx where_insn;
+     rtx pattern;
+{
+  if (! where_insn)
+    return loop_insn_hoist (loop, pattern);
+  return emit_insn_before (pattern, where_insn);
+}
+
+
+/* Emit call insn for PATTERN before WHERE_INSN in basic block
+   WHERE_BB (ignored in the interim) within the loop.  */
+
+static rtx
+loop_call_insn_emit_before (loop, where_bb, where_insn, pattern)
+     const struct loop *loop ATTRIBUTE_UNUSED;
+     basic_block where_bb ATTRIBUTE_UNUSED;
+     rtx where_insn;
+     rtx pattern;
+{
+  return emit_call_insn_before (pattern, where_insn);
+}
+
+
+/* Hoist insn for PATTERN into the loop pre-header.  */
+
+rtx
+loop_insn_hoist (loop, pattern)
+     const struct loop *loop;
+     rtx pattern;
+{
+  return loop_insn_emit_before (loop, 0, loop->start, pattern);
+}
+
+
+/* Hoist call insn for PATTERN into the loop pre-header.  */
+
+static rtx
+loop_call_insn_hoist (loop, pattern)
+     const struct loop *loop;
+     rtx pattern;
+{
+  return loop_call_insn_emit_before (loop, 0, loop->start, pattern);
+}
+
+
+/* Sink insn for PATTERN after the loop end.  */
+
+rtx
+loop_insn_sink (loop, pattern)
+     const struct loop *loop;
+     rtx pattern;
+{
+  return loop_insn_emit_before (loop, 0, loop->sink, pattern);
+}
+
+
+/* If the loop has multiple exits, emit insn for PATTERN before the
+   loop to ensure that it will always be executed no matter how the
+   loop exits.  Otherwise, emit the insn for PATTERN after the loop,
+   since this is slightly more efficient.  */
+
+static rtx
+loop_insn_sink_or_swim (loop, pattern)
+     const struct loop *loop;
+     rtx pattern;
+{
+  if (loop->exit_count)
+    return loop_insn_hoist (loop, pattern);
+  else
+    return loop_insn_sink (loop, pattern);
+}
+\f
+static void
+loop_ivs_dump (loop, file, verbose)
+     const struct loop *loop;
+     FILE *file;
+     int verbose;
+{
+  struct iv_class *bl;
+  int iv_num = 0;
+
+  if (! loop || ! file)
+    return;
+
+  for (bl = LOOP_IVS (loop)->list; bl; bl = bl->next)
+    iv_num++;
+
+  fprintf (file, "Loop %d: %d IV classes\n", loop->num, iv_num);
+
+  for (bl = LOOP_IVS (loop)->list; bl; bl = bl->next)
+    {
+      loop_iv_class_dump (bl, file, verbose);
+      fputc ('\n', file);
+    }
+}
+
+
+static void
+loop_iv_class_dump (bl, file, verbose)
+     const struct iv_class *bl;
+     FILE *file;
+     int verbose ATTRIBUTE_UNUSED;
+{
+  struct induction *v;
+  rtx incr;
+  int i;
+
+  if (! bl || ! file)
+    return;
+
+  fprintf (file, "IV class for reg %d, benefit %d\n",
+          bl->regno, bl->total_benefit);
+
+  fprintf (file, " Init insn %d", INSN_UID (bl->init_insn));
+  if (bl->initial_value)
+    {
+      fprintf (file, ", init val: ");
+      print_simple_rtl (file, bl->initial_value);
+    }
+  if (bl->initial_test)
+    {
+      fprintf (file, ", init test: ");
+      print_simple_rtl (file, bl->initial_test);
+    }
+  fputc ('\n', file);
+
+  if (bl->final_value)
+    {
+      fprintf (file, " Final val: ");
+      print_simple_rtl (file, bl->final_value);
+      fputc ('\n', file);
+    }
+
+  if ((incr = biv_total_increment (bl)))
+    {
+      fprintf (file, " Total increment: ");
+      print_simple_rtl (file, incr);
+      fputc ('\n', file);
+    }
+
+  /* List the increments.  */
+  for (i = 0, v = bl->biv; v; v = v->next_iv, i++)
+    {
+      fprintf (file, " Inc%d: insn %d, incr: ", i, INSN_UID (v->insn));
+      print_simple_rtl (file, v->add_val);
+      fputc ('\n', file);
+    }
+
+  /* List the givs.  */
+  for (i = 0, v = bl->giv; v; v = v->next_iv, i++)
+    {
+      fprintf (file, " Giv%d: insn %d, benefit %d, ", 
+              i, INSN_UID (v->insn), v->benefit);
+      if (v->giv_type == DEST_ADDR)
+         print_simple_rtl (file, v->mem);
+      else
+         print_simple_rtl (file, single_set (v->insn));
+      fputc ('\n', file);
+    }
+}
+
+
+static void
+loop_biv_dump (v, file, verbose)
+     const struct induction *v;
+     FILE *file;
+     int verbose;
+{
+  if (! v || ! file)
+    return;
+
+  fprintf (file,
+          "Biv %d: insn %d",
+          REGNO (v->dest_reg), INSN_UID (v->insn));
+  fprintf (file, " const ");
+  print_simple_rtl (file, v->add_val);
+
+  if (verbose && v->final_value)
+    {
+      fputc ('\n', file);  
+      fprintf (file, " final ");
+      print_simple_rtl (file, v->final_value);
+    }
+
+  fputc ('\n', file);
+}
+
+
+static void
+loop_giv_dump (v, file, verbose)
+     const struct induction *v;
+     FILE *file;
+     int verbose;
+{
+  if (! v || ! file)
+    return;
+
+  if (v->giv_type == DEST_REG)
+    fprintf (file, "Giv %d: insn %d",
+            REGNO (v->dest_reg),  INSN_UID (v->insn)); 
+  else
+    fprintf (file, "Dest address: insn %d",
+            INSN_UID (v->insn));
+  
+  fprintf (file, " src reg %d benefit %d",
+          REGNO (v->src_reg), v->benefit);
+  fprintf (file, " lifetime %d",
+          v->lifetime);
+  
+  if (v->replaceable)
+    fprintf (file, " replaceable");
+  
+  if (v->no_const_addval)
+    fprintf (file, " ncav");
+  
+  if (v->ext_dependant)
+    {
+      switch (GET_CODE (v->ext_dependant))
+       {
+       case SIGN_EXTEND:
+         fprintf (file, " ext se");
+         break;
+       case ZERO_EXTEND:
+         fprintf (file, " ext ze");
+         break;
+       case TRUNCATE:
+         fprintf (file, " ext tr");
+             break;
+       default:
+         abort ();
+       }
+    }
+
+  fputc ('\n', file);  
+  fprintf (file, " mult ");
+  print_simple_rtl (file, v->mult_val);
+
+  fputc ('\n', file);  
+  fprintf (file, " add  ");
+  print_simple_rtl (file, v->add_val);
+
+  if (verbose && v->final_value)
+    {
+      fputc ('\n', file);  
+      fprintf (file, " final ");
+      print_simple_rtl (file, v->final_value);
+    }
+
+  fputc ('\n', file);  
+}
+
+
+void
+debug_ivs (loop)
+     const struct loop *loop;
+{
+  loop_ivs_dump (loop, stderr, 1);
+}
+
+
+void
+debug_iv_class (bl)
+     const struct iv_class *bl;
+{
+  loop_iv_class_dump (bl, stderr, 1);
+}
+
+
+void
+debug_biv (v)
+     const struct induction *v;
+{
+  loop_biv_dump (v, stderr, 1);
+}
+
+
+void
+debug_giv (v)
+     const struct induction *v;
+{
+  loop_giv_dump (v, stderr, 1);
+}
+
+
 #define LOOP_BLOCK_NUM_1(INSN) \
 ((INSN) ? (BLOCK_FOR_INSN (INSN) ? BLOCK_NUM (INSN) : - 1) : -1)
 
@@ -9982,10 +9763,11 @@ replace_label (x, data)
 
 #define LOOP_INSN_UID(INSN) ((INSN) ? INSN_UID (INSN) : -1)
 
-static void loop_dump_aux (loop, file, verbose)
+static void
+loop_dump_aux (loop, file, verbose)
      const struct loop *loop;
      FILE *file;
-     int verbose;
+     int verbose ATTRIBUTE_UNUSED;
 {
   rtx label;
 
@@ -9998,7 +9780,7 @@ static void loop_dump_aux (loop, file, verbose)
       || GET_CODE (PREV_INSN (loop->first->head)) != NOTE
       || NOTE_LINE_NUMBER (PREV_INSN (loop->first->head))
       != NOTE_INSN_LOOP_BEG)
-    fprintf (file, ";;  No NOTE_INSN_LOOP_BEG at %d\n", 
+    fprintf (file, ";;  No NOTE_INSN_LOOP_BEG at %d\n",
             INSN_UID (PREV_INSN (loop->first->head)));
   if (! NEXT_INSN (loop->last->end)
       || GET_CODE (NEXT_INSN (loop->last->end)) != NOTE
@@ -10023,7 +9805,7 @@ static void loop_dump_aux (loop, file, verbose)
               LOOP_INSN_UID (loop->end));
       fprintf (file, ";;  top %d (%d), scan start %d (%d)\n",
               LOOP_BLOCK_NUM (loop->top),
-              LOOP_INSN_UID (loop->top) ,
+              LOOP_INSN_UID (loop->top),
               LOOP_BLOCK_NUM (loop->scan_start),
               LOOP_INSN_UID (loop->scan_start));
       fprintf (file, ";;  exit_count %d", loop->exit_count);
@@ -10037,7 +9819,7 @@ static void loop_dump_aux (loop, file, verbose)
            }
        }
       fputs ("\n", file);
-      
+
       /* This can happen when a marked loop appears as two nested loops,
         say from while (a || b) {}.  The inner loop won't match
         the loop markers but the outer one will.  */
@@ -10045,7 +9827,6 @@ static void loop_dump_aux (loop, file, verbose)
        fprintf (file, ";;  NOTE_INSN_LOOP_CONT not in loop latch\n");
     }
 }
-  
 
 /* Call this function from the debugger to dump LOOP.  */
 
@@ -10055,3 +9836,12 @@ debug_loop (loop)
 {
   flow_loop_dump (loop, stderr, loop_dump_aux, 1);
 }
+
+/* Call this function from the debugger to dump LOOPS.  */
+
+void
+debug_loops (loops)
+     const struct loops *loops;
+{
+  flow_loops_dump (loops, stderr, loop_dump_aux, 1);
+}