OSDN Git Service

Fix for PR 3128, IA-64 linux kernel miscompile
[pf3gnuchains/gcc-fork.git] / gcc / loop.c
index dc91761..ec8dc0a 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.
 
@@ -44,7 +44,6 @@ Boston, MA 02111-1307, USA.  */
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "insn-config.h"
-#include "insn-flags.h"
 #include "regs.h"
 #include "recog.h"
 #include "flags.h"
@@ -53,6 +52,15 @@ Boston, MA 02111-1307, USA.  */
 #include "cselib.h"
 #include "except.h"
 #include "toplev.h"
+#include "predict.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.
@@ -144,12 +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 ((struct loop_regs *, rtx, rtx,
-                                  varray_type, rtx *));
-
-static void count_loop_regs_set PARAMS ((const struct loop*,
-                                        varray_type, varray_type,
-                                        int *, int));
+static void count_one_set PARAMS ((struct loop_regs *, rtx, rtx, rtx *));
 static void note_addr_stored PARAMS ((rtx, rtx, void *));
 static void note_set_pseudo_multiple_uses PARAMS ((rtx, rtx, void *));
 static int loop_reg_used_before_p PARAMS ((const struct loop *, rtx, rtx));
@@ -163,6 +166,7 @@ static void ignore_some_movables PARAMS ((struct loop_movables *));
 static void force_movables PARAMS ((struct loop_movables *));
 static void combine_movables PARAMS ((struct loop_movables *,
                                      struct loop_regs *));
+static int num_unmoved_movables PARAMS ((const struct loop *));
 static int regs_match_p PARAMS ((rtx, rtx, struct loop_movables *));
 static int rtx_equal_for_loop_p PARAMS ((rtx, rtx, struct loop_movables *,
                                         struct loop_regs *));
@@ -173,8 +177,22 @@ static void loop_movables_add PARAMS((struct loop_movables *,
                                      struct movable *));
 static void loop_movables_free PARAMS((struct loop_movables *));
 static int count_nonfixed_reads PARAMS ((const struct loop *, rtx));
-static void strength_reduce PARAMS ((struct loop *, int, int));
-static void find_single_use_in_loop PARAMS ((rtx, rtx, varray_type));
+static void loop_bivs_find PARAMS((struct loop *));
+static void loop_bivs_init_find PARAMS((struct loop *));
+static void loop_bivs_check PARAMS((struct loop *));
+static void loop_givs_find PARAMS((struct loop *));
+static void loop_givs_check PARAMS((struct loop *));
+static int loop_biv_eliminable_p PARAMS((struct loop *, struct iv_class *,
+                                        int, int));
+static int loop_giv_reduce_benefit PARAMS((struct loop *, struct iv_class *,
+                                          struct induction *, rtx));
+static void loop_givs_dead_check PARAMS((struct loop *, struct iv_class *));
+static void loop_givs_reduce PARAMS((struct loop *, struct iv_class *));
+static void loop_givs_rescan PARAMS((struct loop *, struct iv_class *,
+                                    rtx *));
+static void loop_ivs_free PARAMS((struct loop *));
+static void strength_reduce PARAMS ((struct loop *, int));
+static void find_single_use_in_loop PARAMS ((struct loop_regs *, rtx, rtx));
 static int valid_initial_value_p PARAMS ((rtx, rtx, int, rtx));
 static void find_mem_givs PARAMS ((const struct loop *, rtx, rtx, int, int));
 static void record_biv PARAMS ((struct loop *, struct induction *,
@@ -182,6 +200,10 @@ static void record_biv PARAMS ((struct loop *, struct induction *,
                                int, int));
 static void check_final_value PARAMS ((const struct loop *,
                                       struct induction *));
+static void loop_ivs_dump PARAMS((const struct loop *, FILE *, int));
+static void loop_iv_class_dump PARAMS((const struct iv_class *, FILE *, int));
+static void loop_biv_dump PARAMS((const struct induction *, FILE *, int));
+static void loop_giv_dump PARAMS((const struct induction *, FILE *, int));
 static void record_giv PARAMS ((const struct loop *, struct induction *,
                                rtx, rtx, rtx, rtx, rtx, rtx, int,
                                enum g_types, int, int, rtx *));
@@ -206,13 +228,14 @@ static int product_cheap_p PARAMS ((rtx, rtx));
 static int maybe_eliminate_biv PARAMS ((const struct loop *, struct iv_class *,
                                        int, int, int));
 static int maybe_eliminate_biv_1 PARAMS ((const struct loop *, rtx, rtx,
-                                         struct iv_class *, int, rtx));
+                                         struct iv_class *, int,
+                                         basic_block, rtx));
 static int last_use_this_basic_block PARAMS ((rtx, rtx));
 static void record_initial PARAMS ((rtx, rtx, void *));
 static void update_reg_last_use PARAMS ((rtx, rtx));
 static rtx next_insn_in_loop PARAMS ((const struct loop *, rtx));
-static void load_mems_and_recount_loop_regs_set PARAMS ((const struct loop*,
-                                                        int *));
+static void loop_regs_scan PARAMS ((const struct loop *, int));
+static int count_insns_in_loop PARAMS ((const struct loop *));
 static void load_mems PARAMS ((const struct loop *));
 static int insert_loop_mem PARAMS ((rtx *, void *));
 static int replace_loop_mem PARAMS ((rtx *, void *));
@@ -226,9 +249,23 @@ 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));
+static void loop_delete_insns PARAMS ((rtx, rtx));
+void debug_ivs PARAMS ((const struct loop *));
+void debug_iv_class PARAMS ((const struct iv_class *));
+void debug_biv PARAMS ((const struct induction *));
+void debug_giv PARAMS ((const struct induction *));
 void debug_loop PARAMS ((const struct loop *));
 void debug_loops PARAMS ((const struct loops *));
 
@@ -324,7 +361,6 @@ loop_optimize (f, dumpfile, flags)
   struct loops loops_data;
   struct loops *loops = &loops_data;
   struct loop_info *loops_info;
-  static char *moved_once;
 
   loop_dump_stream = dumpfile;
 
@@ -351,8 +387,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;
@@ -422,9 +456,6 @@ loop_optimize (f, dumpfile, flags)
   for (i = max_loop_num - 1; i >= 0; i--)
     {
       struct loop *loop = &loops->array[i];
-      struct loop_regs *regs = LOOP_REGS (loop);
-
-      regs->moved_once = moved_once;
 
       if (! loop->invalid && loop->end)
        scan_loop (loop, flags);
@@ -440,7 +471,6 @@ loop_optimize (f, dumpfile, flags)
   end_alias_analysis ();
 
   /* Clean up.  */
-  free (moved_once);
   free (uid_luid);
   free (uid_loop);
   free (loops_info);
@@ -518,13 +548,11 @@ 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
@@ -553,6 +581,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);
@@ -599,43 +636,11 @@ scan_loop (loop, flags)
       return;
     }
 
-  /* Count number of times each reg is set during this loop.  Set
-     VARRAY_CHAR (regs->may_not_optimize, I) if it is not safe to move
-     out the setting of register I.  Set VARRAY_RTX
-     (regs->single_usage, I).  */
-
-  /* Allocate extra space for REGS that might be created by
-     load_mems.  We allocate a little extra slop as well, in the hopes
-     that even after the moving of movables creates some new registers
-     we won't have to reallocate these arrays.  However, we do grow
-     the arrays, if necessary, in load_mems_recount_loop_regs_set.  */
-  nregs = max_reg_num () + loop_info->mems_idx + 16;
-  VARRAY_INT_INIT (regs->set_in_loop, nregs, "set_in_loop");
-  VARRAY_INT_INIT (regs->n_times_set, nregs, "n_times_set");
-  VARRAY_CHAR_INIT (regs->may_not_optimize, nregs, "may_not_optimize");
-  VARRAY_RTX_INIT (regs->single_usage, nregs, "single_usage");
-
-  regs->num = nregs;
-
-  count_loop_regs_set (loop, regs->may_not_optimize, regs->single_usage,
-                      &insn_count, nregs);
-
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      VARRAY_CHAR (regs->may_not_optimize, i) = 1;
-      VARRAY_INT (regs->set_in_loop, i) = 1;
-    }
-
-#ifdef AVOID_CCMODE_COPIES
-  /* Don't try to move insns which set CC registers if we should not
-     create CCmode register copies.  */
-  for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
-    if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
-      VARRAY_CHAR (regs->may_not_optimize, i) = 1;
-#endif
-
-  bcopy ((char *) &regs->set_in_loop->data,
-        (char *) &regs->n_times_set->data, nregs * sizeof (int));
+  /* Allocate extra space for REGs that might be created by load_mems.
+     We allocate a little extra slop as well, in the hopes that we
+     won't have to reallocate the regs array.  */
+  loop_regs_scan (loop, loop_info->mems_idx + 16);
+  insn_count = count_insns_in_loop (loop);
 
   if (loop_dump_stream)
     {
@@ -647,7 +652,7 @@ scan_loop (loop, flags)
     }
 
   /* Scan through the loop finding insns that are safe to move.
-     Set regs->set_in_loop negative for the reg being set, so that
+     Set REGS->ARRAY[I].SET_IN_LOOP negative for the reg I being set, so that
      this reg will be considered invariant for subsequent insns.
      We consider whether subsequent insns use the reg
      in deciding whether it is worth actually moving.
@@ -666,7 +671,7 @@ scan_loop (loop, flags)
       if (GET_CODE (p) == INSN
          && (set = single_set (p))
          && GET_CODE (SET_DEST (set)) == REG
-         && ! VARRAY_CHAR (regs->may_not_optimize, REGNO (SET_DEST (set))))
+         && ! regs->array[REGNO (SET_DEST (set))].may_not_optimize)
        {
          int tem1 = 0;
          int tem2 = 0;
@@ -730,13 +735,11 @@ scan_loop (loop, flags)
          else if ((tem = loop_invariant_p (loop, src))
                   && (dependencies == 0
                       || (tem2 = loop_invariant_p (loop, dependencies)) != 0)
-                  && (VARRAY_INT (regs->set_in_loop,
-                                  REGNO (SET_DEST (set))) == 1
+                  && (regs->array[REGNO (SET_DEST (set))].set_in_loop == 1
                       || (tem1
                           = consec_sets_invariant_p
                           (loop, SET_DEST (set),
-                           VARRAY_INT (regs->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
@@ -764,12 +767,13 @@ scan_loop (loop, flags)
                 SMALL_REGISTER_CLASSES and SET_SRC is a hard register.  */
 
              if (loop_info->has_call
-                 && VARRAY_RTX (regs->single_usage, regno) != 0
-                 && VARRAY_RTX (regs->single_usage, regno) != const0_rtx
+                 && 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 (regs->single_usage, regno)))
-                 && VARRAY_INT (regs->set_in_loop, regno) == 1
+                     == INSN_UID (regs->array[regno].single_usage))
+                 && regs->array[regno].set_in_loop == 1
+                 && GET_CODE (SET_SRC (set)) != ASM_OPERANDS
                  && ! side_effects_p (SET_SRC (set))
                  && ! find_reg_note (p, REG_RETVAL, NULL_RTX)
                  && (! SMALL_REGISTER_CLASSES
@@ -779,26 +783,22 @@ 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
-                                          (regs->single_usage, regno))
-                 && no_labels_between_p (p, VARRAY_RTX (regs->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
-                                          (regs->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 (regs->single_usage, regno))
-                   = replace_rtx (REG_NOTES (VARRAY_RTX
-                                             (regs->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 (regs->set_in_loop, regno) = 0;
+                 regs->array[regno].set_in_loop = 0;
                  continue;
                }
 
@@ -809,8 +809,7 @@ scan_loop (loop, flags)
              m->dependencies = dependencies;
              m->set_dest = SET_DEST (set);
              m->force = 0;
-             m->consec = VARRAY_INT (regs->set_in_loop,
-                                     REGNO (SET_DEST (set))) - 1;
+             m->consec = regs->array[REGNO (SET_DEST (set))].set_in_loop - 1;
              m->done = 0;
              m->forces = 0;
              m->partial = 0;
@@ -823,16 +822,13 @@ 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 (regs->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 (regs->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.  */
              loop_movables_add (movables, m);
 
@@ -887,10 +883,10 @@ scan_loop (loop, flags)
                   && !reg_mentioned_p (SET_DEST (set), SET_SRC (set1)))
            {
              register int regno = REGNO (SET_DEST (set));
-             if (VARRAY_INT (regs->set_in_loop, regno) == 2)
+             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);
@@ -921,12 +917,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
@@ -934,10 +927,9 @@ 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 (regs->set_in_loop, regno) = -1;
+                 regs->array[regno].set_in_loop = -1;
                  /* Add M to the end of the chain MOVABLES.  */
                  loop_movables_add (movables, m);
                }
@@ -997,7 +989,7 @@ scan_loop (loop, flags)
   combine_movables (movables, regs);
 
   /* Now consider each movable insn to decide whether it is worth moving.
-     Store 0 in regs->set_in_loop for each reg that is moved.
+     Store 0 in regs->array[I].set_in_loop for each reg I that is moved.
 
      Generally this increases code size, so do not move moveables when
      optimizing for code size.  */
@@ -1006,15 +998,19 @@ scan_loop (loop, flags)
     move_movables (loop, movables, threshold, insn_count);
 
   /* Now candidates that still are negative are those not moved.
-     Change regs->set_in_loop to indicate that those are not actually
+     Change regs->array[I].set_in_loop to indicate that those are not actually
      invariant.  */
-  for (i = 0; i < nregs; i++)
-    if (VARRAY_INT (regs->set_in_loop, i) < 0)
-      VARRAY_INT (regs->set_in_loop, i) = VARRAY_INT (regs->n_times_set, i);
+  for (i = 0; i < regs->num; i++)
+    if (regs->array[i].set_in_loop < 0)
+      regs->array[i].set_in_loop = regs->array[i].n_times_set;
 
   /* Now that we've moved some things out of the loop, we might be able to
      hoist even more memory references.  */
-  load_mems_and_recount_loop_regs_set (loop, &insn_count);
+  load_mems (loop);
+
+  /* Recalculate regs->array if load_mems has created new registers.  */
+  if (max_reg_num () > regs->num)
+    loop_regs_scan (loop, 0);
 
   for (update_start = loop_start;
        PREV_INSN (update_start)
@@ -1032,7 +1028,7 @@ scan_loop (loop, flags)
        /* Ensure our label doesn't go away.  */
        LABEL_NUSES (update_end)++;
 
-      strength_reduce (loop, insn_count, flags);
+      strength_reduce (loop, flags);
 
       reg_scan_update (update_start, update_end, loop_max_reg);
       loop_max_reg = max_reg_num ();
@@ -1046,10 +1042,9 @@ scan_loop (loop, flags)
   /* The movable information is required for strength reduction.  */
   loop_movables_free (movables);
 
-  VARRAY_FREE (regs->single_usage);
-  VARRAY_FREE (regs->set_in_loop);
-  VARRAY_FREE (regs->n_times_set);
-  VARRAY_FREE (regs->may_not_optimize);
+  free (regs->array);
+  regs->array = 0;
+  regs->num = 0;
 }
 \f
 /* Add elements to *OUTPUT to record all the pseudo-regs
@@ -1328,7 +1323,7 @@ combine_movables (movables, regs)
   /* Perhaps testing m->consec_sets would be more appropriate here?  */
 
   for (m = movables->head; m; m = m->next)
-    if (m->match == 0 && VARRAY_INT (regs->n_times_set, m->regno) == 1
+    if (m->match == 0 && regs->array[m->regno].n_times_set == 1
        && !m->partial)
       {
        register struct movable *m1;
@@ -1340,8 +1335,8 @@ combine_movables (movables, regs)
        /* We want later insns to match the first one.  Don't make the first
           one match any later ones.  So start this loop at m->next.  */
        for (m1 = m->next; m1; m1 = m1->next)
-         if (m != m1 && m1->match == 0 && VARRAY_INT (regs->n_times_set,
-                                                      m1->regno) == 1
+         if (m != m1 && m1->match == 0 
+             && 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.  */
@@ -1393,8 +1388,8 @@ combine_movables (movables, regs)
            && 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)
              {
@@ -1412,8 +1407,8 @@ combine_movables (movables, regs)
               already combined together.  */
            for (m1 = movables->head; m1 != m; m1 = m1->next)
              if (m1 == m0 || (m1->partial && m1->match == m0))
-               if (! (uid_luid[REGNO_FIRST_UID (m1->regno)] > last
-                      || uid_luid[REGNO_LAST_UID (m1->regno)] < first))
+               if (! (REGNO_FIRST_LUID (m1->regno) > last
+                      || REGNO_LAST_LUID (m1->regno) < first))
                  goto overlap;
 
            /* No overlap: we can combine this with the others.  */
@@ -1430,6 +1425,24 @@ combine_movables (movables, regs)
   /* Clean up.  */
   free (matched_regs);
 }
+
+/* Returns the number of movable instructions in LOOP that were not
+   moved outside the loop.  */
+
+static int
+num_unmoved_movables (loop)
+     const struct loop *loop;
+{
+  int num = 0;
+  struct movable *m;
+
+  for (m = LOOP_MOVABLES (loop)->head; m; m = m->next)
+    if (!m->done)
+      ++num;
+
+  return num;
+}
+
 \f
 /* Return 1 if regs X and Y will become the same if moved.  */
 
@@ -1483,7 +1496,7 @@ rtx_equal_for_loop_p (x, y, movables, regs)
 
   /* If we have a register and a constant, they may sometimes be
      equal.  */
-  if (GET_CODE (x) == REG && VARRAY_INT (regs->set_in_loop, REGNO (x)) == -2
+  if (GET_CODE (x) == REG && regs->array[REGNO (x)].set_in_loop == -2
       && CONSTANT_P (y))
     {
       for (m = movables->head; m; m = m->next)
@@ -1491,8 +1504,7 @@ rtx_equal_for_loop_p (x, y, movables, regs)
            && rtx_equal_p (m->set_src, y))
          return 1;
     }
-  else if (GET_CODE (y) == REG && VARRAY_INT (regs->set_in_loop,
-                                             REGNO (y)) == -2
+  else if (GET_CODE (y) == REG && regs->array[REGNO (y)].set_in_loop == -2
           && CONSTANT_P (x))
     {
       for (m = movables->head; m; m = m->next)
@@ -1579,7 +1591,8 @@ rtx_equal_for_loop_p (x, y, movables, regs)
 }
 \f
 /* If X contains any LABEL_REF's, add REG_LABEL notes for them to all
-  insns in INSNS which use the reference.  */
+   insns in INSNS which use the reference.  LABEL_NUSES for CODE_LABEL
+   references is incremented once for each added note. */
 
 static void
 add_label_notes (x, insns)
@@ -1600,8 +1613,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);
@@ -1639,8 +1656,6 @@ move_movables (loop, movables, threshold, insn_count)
   rtx *reg_map = (rtx *) xcalloc (nregs, sizeof (rtx));
   char *already_moved = (char *) xcalloc (nregs, sizeof (char));
 
-  movables->num = 0;
-
   for (m = movables->head; m; m = m->next)
     {
       /* Describe this movable insn.  */
@@ -1669,9 +1684,6 @@ move_movables (loop, movables, threshold, insn_count)
                     INSN_UID (m->forces->insn));
        }
 
-      /* Count movables.  Value used in heuristics in strength_reduce.  */
-      movables->num++;
-
       /* Ignore the insn if it's already done (it matched something else).
         Otherwise, see if it is now safe to move.  */
 
@@ -1699,7 +1711,7 @@ move_movables (loop, movables, threshold, insn_count)
          if (loop_dump_stream)
            fprintf (loop_dump_stream, "savings %d ", savings);
 
-         if (regs->moved_once[regno] && loop_dump_stream)
+         if (regs->array[regno].moved_once && loop_dump_stream)
            fprintf (loop_dump_stream, "halved since already moved ");
 
          /* An insn MUST be moved if we already moved something else
@@ -1718,9 +1730,9 @@ move_movables (loop, movables, threshold, insn_count)
          if (already_moved[regno]
              || flag_move_all_movables
              || (threshold * savings * m->lifetime) >=
-                (regs->moved_once[regno] ? insn_count * 2 : insn_count)
+                (regs->array[regno].moved_once ? insn_count * 2 : insn_count)
              || (m->forces && m->forces->done
-                 && VARRAY_INT (regs->n_times_set, m->forces->regno) == 1))
+                 && regs->array[m->forces->regno].n_times_set == 1))
            {
              int count;
              register struct movable *m1;
@@ -1739,7 +1751,7 @@ move_movables (loop, movables, threshold, insn_count)
                  for (m1 = m; m1->match; m1 = m1->match);
                  newpat = gen_move_insn (SET_DEST (PATTERN (m->insn)),
                                          SET_DEST (PATTERN (m1->insn)));
-                 i1 = emit_insn_before (newpat, loop_start);
+                 i1 = loop_insn_hoist (loop, newpat);
 
                  /* Mark the moved, invariant reg as being allowed to
                     share a hard reg with the other matching invariant.  */
@@ -1763,7 +1775,7 @@ move_movables (loop, movables, threshold, insn_count)
                 the move insn before the loop.  */
              else if (m->move_insn)
                {
-                 rtx i1, temp;
+                 rtx i1, temp, seq;
 
                  for (count = m->consec; count >= 0; count--)
                    {
@@ -1800,11 +1812,12 @@ move_movables (loop, movables, threshold, insn_count)
                  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,
@@ -1890,13 +1903,13 @@ move_movables (loop, movables, threshold, insn_count)
                              if (GET_CODE (temp) == CALL_INSN
                                  && fn_address != 0
                                  && reg_referenced_p (fn_reg, body))
-                               emit_insn_after (gen_move_insn (fn_reg,
-                                                               fn_address),
-                                                fn_address_insn);
+                               loop_insn_emit_after (loop, 0, fn_address_insn,
+                                                     gen_move_insn
+                                                     (fn_reg, fn_address));
 
                              if (GET_CODE (temp) == CALL_INSN)
                                {
-                                 i1 = emit_call_insn_before (body, loop_start);
+                                 i1 = loop_call_insn_hoist (loop, body);
                                  /* Because the USAGE information potentially
                                     contains objects other than hard registers
                                     we need to copy it.  */
@@ -1905,7 +1918,7 @@ move_movables (loop, movables, threshold, insn_count)
                                      = copy_rtx (CALL_INSN_FUNCTION_USAGE (temp));
                                }
                              else
-                               i1 = emit_insn_before (body, loop_start);
+                               i1 = loop_insn_hoist (loop, body);
                              if (first == 0)
                                first = i1;
                              if (temp == fn_address_insn)
@@ -1938,11 +1951,11 @@ move_movables (loop, movables, threshold, insn_count)
                            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.  */
@@ -1952,16 +1965,18 @@ move_movables (loop, movables, threshold, insn_count)
                        }
                      else if (count == m->consec && m->move_insn_first)
                        {
+                         rtx seq;
                          /* The SET_SRC might not be invariant, so we must
                             use the REG_EQUAL note.  */
                          start_sequence ();
                          emit_move_insn (m->set_dest, m->set_src);
                          temp = get_insns ();
+                         seq = 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
@@ -1969,7 +1984,7 @@ move_movables (loop, movables, threshold, insn_count)
                                                   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)
                        {
@@ -2026,11 +2041,11 @@ move_movables (loop, movables, threshold, insn_count)
              already_moved[regno] = 1;
 
              /* This reg has been moved out of one loop.  */
-             regs->moved_once[regno] = 1;
+             regs->array[regno].moved_once = 1;
 
              /* The reg set here is now invariant.  */
              if (! m->partial)
-               VARRAY_INT (regs->set_in_loop, regno) = 0;
+               regs->array[regno].set_in_loop = 0;
 
              m->done = 1;
 
@@ -2038,12 +2053,12 @@ move_movables (loop, movables, threshold, insn_count)
                 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.  */
@@ -2094,7 +2109,7 @@ move_movables (loop, movables, threshold, insn_count)
                      /* The reg merged here is now invariant,
                         if the reg it matches is invariant.  */
                      if (! m->partial)
-                       VARRAY_INT (regs->set_in_loop, m1->regno) = 0;
+                       regs->array[m1->regno].set_in_loop = 0;
                    }
            }
          else if (loop_dump_stream)
@@ -2272,7 +2287,7 @@ count_nonfixed_reads (loop, x)
 }
 \f
 /* Scan a loop setting the elements `cont', `vtop', `loops_enclosed',
-   `has_call', `has_volatile', `has_tablejump',
+   `has_call', `has_nonconst_call', `has_volatile', `has_tablejump',
    `unknown_address_altered', `unknown_constant_address_altered', and
    `num_mem_sets' in LOOP.  Also, fill in the array `mems' and the
    list `store_mems' in LOOP.  */
@@ -2293,7 +2308,9 @@ 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;
@@ -2306,6 +2323,17 @@ prescan_loop (loop)
   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))
     {
@@ -2325,7 +2353,10 @@ prescan_loop (loop)
       else if (GET_CODE (insn) == CALL_INSN)
        {
          if (! CONST_CALL_P (insn))
-           loop_info->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)
@@ -2392,7 +2423,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
@@ -2995,8 +3026,8 @@ note_set_pseudo_multiple_uses (x, y, data)
   /* If we do not have usage information, or if we know the register
      is used more than once, note that fact for check_dbra_loop.  */
   if (REGNO (x) >= max_reg_before_loop
-      || ! VARRAY_RTX (regs->single_usage, REGNO (x))
-      || VARRAY_RTX (regs->single_usage, REGNO (x)) == const0_rtx)
+      || ! regs->array[REGNO (x)].single_usage
+      || regs->array[REGNO (x)].single_usage == const0_rtx)
     regs->multiple_uses = 1;
 }
 \f
@@ -3064,10 +3095,10 @@ loop_invariant_p (loop, x)
          && REGNO (x) < FIRST_PSEUDO_REGISTER && call_used_regs[REGNO (x)])
        return 0;
 
-      if (VARRAY_INT (regs->set_in_loop, REGNO (x)) < 0)
+      if (regs->array[REGNO (x)].set_in_loop < 0)
        return 2;
 
-      return VARRAY_INT (regs->set_in_loop, REGNO (x)) == 0;
+      return regs->array[REGNO (x)].set_in_loop == 0;
 
     case MEM:
       /* Volatile memory references must be rejected.  Do this before
@@ -3152,7 +3183,7 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
   rtx temp;
   /* Number of sets we have to insist on finding after INSN.  */
   int count = n_sets - 1;
-  int old = VARRAY_INT (regs->set_in_loop, regno);
+  int old = regs->array[regno].set_in_loop;
   int value = 0;
   int this;
 
@@ -3160,7 +3191,7 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
   if (n_sets == 127)
     return 0;
 
-  VARRAY_INT (regs->set_in_loop, regno) = 0;
+  regs->array[regno].set_in_loop = 0;
 
   while (count > 0)
     {
@@ -3199,12 +3230,12 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
        count--;
       else if (code != NOTE)
        {
-         VARRAY_INT (regs->set_in_loop, regno) = old;
+         regs->array[regno].set_in_loop = old;
          return 0;
        }
     }
 
-  VARRAY_INT (regs->set_in_loop, regno) = old;
+  regs->array[regno].set_in_loop = old;
   /* If loop_invariant_p ever returned 2, we return 2.  */
   return 1 + (value & 2);
 }
@@ -3247,19 +3278,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)
@@ -3269,34 +3300,34 @@ find_single_use_in_loop (insn, x, usage)
         show up as a potential movable so we don't care how USAGE is set
         for it.  */
       if (GET_CODE (SET_DEST (x)) != REG)
-       find_single_use_in_loop (insn, SET_DEST (x), usage);
-      find_single_use_in_loop (insn, SET_SRC (x), usage);
+       find_single_use_in_loop (regs, insn, SET_DEST (x));
+      find_single_use_in_loop (regs, insn, SET_SRC (x));
     }
   else
     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
       {
        if (fmt[i] == 'e' && XEXP (x, i) != 0)
-         find_single_use_in_loop (insn, XEXP (x, i), usage);
+         find_single_use_in_loop (regs, insn, XEXP (x, i));
        else if (fmt[i] == 'E')
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           find_single_use_in_loop (insn, XVECEXP (x, i, j), usage);
+           find_single_use_in_loop (regs, insn, XVECEXP (x, i, j));
       }
 }
 \f
 /* Count and record any set in X which is contained in INSN.  Update
-   MAY_NOT_MOVE and LAST_SET for any register set in X.  */
+   REGS->array[I].MAY_NOT_OPTIMIZE and LAST_SET for any register I set
+   in X.  */
 
 static void
-count_one_set (regs, insn, x, may_not_move, last_set)
+count_one_set (regs, insn, x, last_set)
      struct loop_regs *regs;
      rtx insn, x;
-     varray_type may_not_move;
      rtx *last_set;
 {
   if (GET_CODE (x) == CLOBBER && GET_CODE (XEXP (x, 0)) == REG)
     /* Don't move a reg that has an explicit clobber.
        It's not worth the pain to try to do it correctly.  */
-    VARRAY_CHAR (may_not_move, REGNO (XEXP (x, 0))) = 1;
+    regs->array[REGNO (XEXP (x, 0))].may_not_optimize = 1;
 
   if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
     {
@@ -3313,85 +3344,21 @@ count_one_set (regs, 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 (regs->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 (regs->set_in_loop, regno) < 127)
-           ++VARRAY_INT (regs->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 REGS->SET_IN_LOOP at the index of each register
-   that is modified by an insn between FROM and TO.
-   If the value of an element of REGS->SET_IN_LOOP becomes 127 or more,
-   stop incrementing it, to avoid overflow.
-
-   Store in SINGLE_USAGE[I] the single insn in which register I is
-   used, if it is only used once.  Otherwise, it is set to 0 (for no
-   uses) or const0_rtx for more than one use.  This parameter may be zero,
-   in which case this processing is not done.
-
-   Store in *COUNT_PTR the number of actual instruction
-   in the loop.  We use this to decide what is worth moving out.  */
-
-/* last_set[n] is nonzero iff reg n has been set in the current basic block.
-   In that case, it is the insn that last set reg n.  */
-
-static void
-count_loop_regs_set (loop, may_not_move, single_usage, count_ptr, nregs)
-     const struct loop *loop;
-     varray_type may_not_move;
-     varray_type single_usage;
-     int *count_ptr;
-     int nregs;
-{
-  struct loop_regs *regs = LOOP_REGS (loop);
-  register rtx *last_set = (rtx *) xcalloc (nregs, sizeof (rtx));
-  register rtx insn;
-  register int count = 0;
-
-  for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
-       insn = NEXT_INSN (insn))
-    {
-      if (INSN_P (insn))
-       {
-         ++count;
-
-         /* Record registers that have exactly one use.  */
-         find_single_use_in_loop (insn, PATTERN (insn), single_usage);
-
-         /* Include uses in REG_EQUAL notes.  */
-         if (REG_NOTES (insn))
-           find_single_use_in_loop (insn, REG_NOTES (insn), single_usage);
-
-         if (GET_CODE (PATTERN (insn)) == SET
-             || GET_CODE (PATTERN (insn)) == CLOBBER)
-           count_one_set (regs, insn, PATTERN (insn), may_not_move, last_set);
-         else if (GET_CODE (PATTERN (insn)) == PARALLEL)
-           {
-             register int i;
-             for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
-               count_one_set (regs, insn, XVECEXP (PATTERN (insn), 0, i),
-                              may_not_move, last_set);
-           }
-       }
-
-      if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
-       memset ((char *) last_set, 0, nregs * sizeof (rtx));
-    }
-  *count_ptr = count;
-
-  /* Clean up.  */
-  free (last_set);
-}
 \f
 /* Given a loop that is bounded by LOOP->START and LOOP->END and that
    is entered at LOOP->SCAN_START, return 1 if the register set in SET
@@ -3620,80 +3587,33 @@ for_each_insn_in_loop (loop, fncall)
     }
 }
 \f
-/* Perform strength reduction and induction variable elimination.
-
-   Pseudo registers created during this function will be beyond the
-   last valid index in several tables including regs->n_times_set and
-   regno_last_uid.  This does not cause a problem here, because the
-   added registers cannot be givs outside of their loop, and hence
-   will never be reconsidered.  But scan_loop must check regnos to
-   make sure they are in bounds.  */
-
 static void
-strength_reduce (loop, insn_count, flags)
+loop_bivs_find (loop)
      struct loop *loop;
-     int insn_count;
-     int flags;
 {
-  struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
   struct loop_ivs *ivs = LOOP_IVS (loop);
-  rtx p;
-  /* Temporary list pointers for traversing ivs->loop_iv_list.  */
+  /* Temporary list pointers for traversing ivs->list.  */
   struct iv_class *bl, **backbl;
-  /* Ratio of extra register life span we can justify
-     for saving an instruction.  More if loop doesn't call subroutines
-     since in that case saving an insn makes more difference
-     and more registers are available.  */
-  /* ??? could set this to last value of threshold in move_movables */
-  int threshold = (loop_info->has_call ? 1 : 2) * (3 + n_non_fixed_regs);
-  /* Map of pseudo-register replacements.  */
-  rtx *reg_map = NULL;
-  int reg_map_size;
-  int call_seen;
-  rtx test;
-  rtx end_insert_before;
-  int unrolled_insn_copies = 0;
-  rtx loop_start = loop->start;
-  rtx loop_end = loop->end;
-  rtx test_reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
-
-  VARRAY_INT_INIT (ivs->reg_iv_type, max_reg_before_loop, "reg_iv_type");
-  VARRAY_GENERIC_PTR_INIT (ivs->reg_iv_info, max_reg_before_loop, "reg_iv_info");
-  ivs->reg_biv_class = (struct iv_class **)
-    xcalloc (max_reg_before_loop, sizeof (struct iv_class *));
-
-  ivs->loop_iv_list = 0;
-  addr_placeholder = gen_reg_rtx (Pmode);
-
-  /* Save insn immediately after the loop_end.  Insns inserted after loop_end
-     must be put before this insn, so that they will appear in the right
-     order (i.e. loop order).
 
-     If loop_end is the end of the current function, then emit a
-     NOTE_INSN_DELETED after loop_end and set end_insert_before to the
-     dummy note insn.  */
-  if (NEXT_INSN (loop_end) != 0)
-    end_insert_before = NEXT_INSN (loop_end);
-  else
-    end_insert_before = emit_note_after (NOTE_INSN_DELETED, loop_end);
+  ivs->list = 0;
 
   for_each_insn_in_loop (loop, check_insn_for_bivs);
-
-  /* Scan ivs->loop_iv_list to remove all regs that proved not to be bivs.
+  
+  /* Scan ivs->list to remove all regs that proved not to be bivs.
      Make a sanity check against regs->n_times_set.  */
-  for (backbl = &ivs->loop_iv_list, bl = *backbl; bl; bl = bl->next)
+  for (backbl = &ivs->list, bl = *backbl; bl; bl = bl->next)
     {
       if (REG_IV_TYPE (ivs, bl->regno) != BASIC_INDUCT
          /* Above happens if register modified by subreg, etc.  */
          /* Make sure it is not recognized as a basic induction var: */
-         || VARRAY_INT (regs->n_times_set, bl->regno) != bl->biv_count
+         || regs->array[bl->regno].n_times_set != bl->biv_count
          /* If never incremented, it is invariant that we decided not to
             move.  So leave it alone.  */
          || ! bl->incremented)
        {
          if (loop_dump_stream)
-           fprintf (loop_dump_stream, "Reg %d: biv discarded, %s\n",
+           fprintf (loop_dump_stream, "Biv %d: discarded, %s\n",
                     bl->regno,
                     (REG_IV_TYPE (ivs, bl->regno) != BASIC_INDUCT
                      ? "not induction variable"
@@ -3708,27 +3628,32 @@ strength_reduce (loop, insn_count, flags)
          backbl = &bl->next;
 
          if (loop_dump_stream)
-           fprintf (loop_dump_stream, "Reg %d: biv verified\n", bl->regno);
+           fprintf (loop_dump_stream, "Biv %d: verified\n", bl->regno);
        }
     }
+}
 
-  /* Exit if there are no bivs.  */
-  if (! ivs->loop_iv_list)
-    {
-      /* Can still unroll the loop anyways, but indicate that there is no
-        strength reduction info available.  */
-      if (flags & LOOP_UNROLL)
-       unroll_loop (loop, insn_count, end_insert_before, 0);
 
-      goto egress;
-    }
+/* Determine how BIVS are 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)
@@ -3742,12 +3667,12 @@ strength_reduce (loop, insn_count, flags)
         constants and registers and only certain of those.  */
       if (GET_CODE (p) == JUMP_INSN
          && JUMP_LABEL (p) != 0
-         && next_real_insn (JUMP_LABEL (p)) == next_real_insn (loop_end)
+         && next_real_insn (JUMP_LABEL (p)) == next_real_insn (loop->end)
          && (test = get_condition_for_loop (loop, p)) != 0
          && GET_CODE (XEXP (test, 0)) == REG
          && REGNO (XEXP (test, 0)) < max_reg_before_loop
-         && (bl = ivs->reg_biv_class[REGNO (XEXP (test, 0))]) != 0
-         && valid_initial_value_p (XEXP (test, 1), p, call_seen, loop_start)
+         && (bl = REG_IV_CLASS (ivs, REGNO (XEXP (test, 0)))) != 0
+         && valid_initial_value_p (XEXP (test, 1), p, call_seen, loop->start)
          && bl->init_insn == 0)
        {
          /* If an NE test, we have an initial value!  */
@@ -3761,11 +3686,22 @@ strength_reduce (loop, insn_count, flags)
            bl->initial_test = test;
        }
     }
+}
 
-  /* Look at the each biv and see if we can say anything better about its
-     initial value from any initializing insns set up above.  (This is done
-     in two passes to avoid missing SETs in a PARALLEL.)  */
-  for (backbl = &ivs->loop_iv_list; (bl = *backbl); backbl = &bl->next)
+
+/* Look at the each biv and see if we can say anything better about its
+   initial value from any initializing insns set up above.  (This is done
+   in two passes to avoid missing SETs in a PARALLEL.)  */
+static void
+loop_bivs_check (loop)
+     struct loop *loop;
+{
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  /* Temporary list pointers for traversing ivs->list.  */
+  struct iv_class *bl;
+  struct iv_class **backbl;
+
+  for (backbl = &ivs->list; (bl = *backbl); backbl = &bl->next)
     {
       rtx src;
       rtx note;
@@ -3785,52 +3721,53 @@ 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);
            }
        }
       /* If we can't make it a giv,
-       let biv keep initial value of "itself".  */
+        let biv keep initial value of "itself".  */
       else if (loop_dump_stream)
        fprintf (loop_dump_stream, "is complex\n");
     }
+}
 
-  /* Search the loop for general induction variables.  */
 
+/* Search the loop for general induction variables.  */
+
+static void
+loop_givs_find (loop)
+     struct loop* loop;
+{
   for_each_insn_in_loop (loop, check_insn_for_givs);
+}
 
-  /* 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);
+/* 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.   */
 
-  /* 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.  */
+static void
+loop_givs_check (loop)
+     struct loop *loop;
+{
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  struct iv_class *bl;
 
-  for (bl = ivs->loop_iv_list; bl; bl = bl->next)
+  for (bl = ivs->list; bl; bl = bl->next)
     {
       struct induction *v;
 
@@ -3838,479 +3775,615 @@ strength_reduce (loop, insn_count, flags)
        if (! v->replaceable && ! v->not_replaceable)
          check_final_value (loop, v);
     }
+}
 
-  /* Try to prove that the loop counter variable (if any) is always
-     nonnegative; if so, record that fact with a REG_NONNEG note
-     so that "decrement and branch until zero" insn can be used.  */
-  check_dbra_loop (loop, insn_count);
-
-  /* Create reg_map to hold substitutions for replaceable giv regs.
-     Some givs might have been made from biv increments, so look at
-     ivs->reg_iv_type for a suitable size.  */
-  reg_map_size = ivs->reg_iv_type->num_elements;
-  reg_map = (rtx *) xcalloc (reg_map_size, sizeof (rtx));
 
-  /* Examine each iv class for feasibility of strength reduction/induction
-     variable elimination.  */
+/* 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.  */
 
-  for (bl = ivs->loop_iv_list; bl; bl = bl->next)
-    {
-      struct induction *v;
-      int benefit;
-      int all_reduced;
-      rtx final_value = 0;
+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.  */
 
-      /* 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
+  if (bl->nonneg)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Cannot eliminate nonneg biv %d.\n", bl->regno);
+      return 0;
+    }
 #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));
-           }
-       }
-
-      /* Check each extension dependant 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 (regs, bl);
-
-      /* This will be true at the end, if all givs which depend on this
-        biv have been strength reduced.
-        We can't (currently) eliminate the biv unless this is so.  */
-      all_reduced = 1;
+  /* Check 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;
+}
 
-      /* Check each giv in this class to see if we will benefit by reducing
-        it.  Skip giv's combined with others.  */
-      for (v = bl->giv; v; v = v->next_iv)
-       {
-         struct induction *tv;
-         int add_cost;
 
-         if (v->ignore || v->same)
-           continue;
+/* Reduce each giv of BL that we have decided to reduce.  */
 
-         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.  */
+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
-         /* Attempt to guess whether autoincrement will handle some of the
-            new add insns; if so, increase BENEFIT (undo the subtraction of
-            add_cost that was done above).  */
-         if (v->giv_type == DEST_ADDR
-             /* Increasing the benefit is risky, since this is only a guess.
-                Avoid increasing register pressure in cases where there would
-                be no other benefit from reducing this giv.  */
-             && benefit > 0
-             && GET_CODE (v->mult_val) == CONST_INT)
+         /* If 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 (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;
+             /* 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)
+               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 an insn is not to be strength reduced, then set its ignore
-            flag, and clear 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
-            value after the loop exit.  To make it simple, just reduce all
-            of such giv's whether or not we know they are used after the loop
-            exit.  */
+/* 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.  */
 
-         if ( ! flag_reduce_all_givs && v->lifetime * threshold * benefit < insn_count
-             && ! bl->reversed )
-           {
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream,
-                        "giv of insn %d not worth while, %d vs %d.\n",
-                        INSN_UID (v->insn),
-                        v->lifetime * threshold * benefit, insn_count);
-             v->ignore = 1;
-             all_reduced = 0;
-           }
-         else
-           {
-             /* Check that we can increment the reduced giv without a
-                multiply insn.  If not, reject it.  */
+static void
+loop_givs_dead_check (loop, bl)
+     struct loop *loop ATTRIBUTE_UNUSED;
+     struct iv_class *bl;
+{
+  struct induction *v;
 
-             for (tv = bl->biv; tv; tv = tv->next_iv)
-               if (tv->mult_val == const1_rtx
-                   && ! product_cheap_p (tv->add_val, v->mult_val))
-                 {
-                   if (loop_dump_stream)
-                     fprintf (loop_dump_stream,
-                              "giv of insn %d: would need a multiply.\n",
-                              INSN_UID (v->insn));
-                   v->ignore = 1;
-                   all_reduced = 0;
-                   break;
-                 }
-           }
+  for (v = bl->giv; v; v = v->next_iv)
+    {
+      if (v->ignore
+         || (v->same && v->same->ignore))
+       continue;
+      
+      if (v->giv_type == DEST_REG
+         && REGNO_FIRST_UID (REGNO (v->dest_reg)) == INSN_UID (v->insn))
+       {
+         struct induction *v1;
+         
+         for (v1 = bl->giv; v1; v1 = v1->next_iv)
+           if (REGNO_LAST_UID (REGNO (v->dest_reg)) == INSN_UID (v1->insn))
+             v->maybe_dead = 1;
        }
+    }
+}
 
-      /* 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.  */
-      for (v = bl->giv; v; v = v->next_iv)
-       {
-         if (v->ignore
-             || (v->same && v->same->ignore))
-           continue;
 
-         if (v->giv_type == DEST_REG
-             && REGNO_FIRST_UID (REGNO (v->dest_reg)) == INSN_UID (v->insn))
-           {
-             struct induction *v1;
+static void
+loop_givs_rescan (loop, bl, reg_map)
+     struct loop *loop;
+     struct iv_class *bl;
+     rtx *reg_map;
+{
+  struct induction *v;
 
-             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;
-           }
+  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);
        }
-
-      /* Reduce each giv that we decided to reduce.  */
-
-      for (v = bl->giv; v; v = v->next_iv)
+      else if (GET_CODE (v->new_reg) == REG
+              && GET_CODE (v->add_val) == REG
+              && REG_POINTER (v->add_val))
        {
-         struct induction *tv;
-         if (! v->ignore && v->same == 0)
-           {
-             int auto_inc_opt = 0;
+         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)
+       {
+         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");
+       }
+    }
+}
 
-             /* If the code for derived givs immediately below has already
-                allocated a new_reg, we must keep it.  */
-             if (! v->new_reg)
-               v->new_reg = gen_reg_rtx (v->mode);
 
-#ifdef AUTO_INC_DEC
-             /* If the target has auto-increment addressing modes, and
-                this is an address giv, then try to put the increment
-                immediately after its use, so that flow can create an
-                auto-increment addressing mode.  */
-             if (v->giv_type == DEST_ADDR && bl->biv_count == 1
-                 && bl->biv->always_executed && ! bl->biv->maybe_multiple
-                 /* We don't handle reversed biv's because bl->biv->insn
-                    does not have a valid INSN_LUID.  */
-                 && ! bl->reversed
-                 && v->always_executed && ! v->maybe_multiple
-                 && INSN_UID (v->insn) < max_uid_for_loop)
-               {
-                 /* If other giv's have been combined with this one, then
-                    this will work only if all uses of the other giv's occur
-                    before this giv's insn.  This is difficult to check.
-
-                    We simplify this by looking for the common case where
-                    there is one DEST_REG giv, and this giv's insn is the
-                    last use of the dest_reg of that DEST_REG giv.  If the
-                    increment occurs after the address giv, then we can
-                    perform the optimization.  (Otherwise, the increment
-                    would have to go before other_giv, and we would not be
-                    able to combine it with the address giv to get an
-                    auto-inc address.)  */
-                 if (v->combined_with)
-                   {
-                     struct induction *other_giv = 0;
+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;
 
-                     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;
+  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 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;
-                 }
+#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
 
-                 if (auto_inc_opt)
-                   v->auto_inc_opt = 1;
-               }
-#endif
+  return benefit;
+}
 
-             /* 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);
-               }
+/* Free IV structures for LOOP.  */
 
-             /* Add code at loop start to initialize giv's reduced reg.  */
+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);
 
-             emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value),
-                               v->mult_val, v->add_val, v->new_reg,
-                               loop_start);
-           }
+  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;
+    }
+}
 
-      /* 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".  */
+/* Perform strength reduction and induction variable elimination.
+
+   Pseudo registers created during this function will be beyond the
+   last valid index in several tables including
+   REGS->ARRAY[I].N_TIMES_SET and REGNO_LAST_UID.  This does not cause a
+   problem here, because the added registers cannot be givs outside of
+   their loop, and hence will never be reconsidered.  But scan_loop
+   must check regnos to make sure they are in bounds.  */
+
+static void
+strength_reduce (loop, flags)
+     struct loop *loop;
+     int flags;
+{
+  struct loop_info *loop_info = LOOP_INFO (loop);
+  struct loop_regs *regs = LOOP_REGS (loop);
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+  rtx p;
+  /* Temporary list pointer for traversing ivs->list.  */
+  struct iv_class *bl;
+  /* Ratio of extra register life span we can justify
+     for saving an instruction.  More if loop doesn't call subroutines
+     since in that case saving an insn makes more difference
+     and more registers are available.  */
+  /* ??? could set this to last value of threshold in move_movables */
+  int threshold = (loop_info->has_call ? 1 : 2) * (3 + n_non_fixed_regs);
+  /* Map of pseudo-register replacements.  */
+  rtx *reg_map = NULL;
+  int reg_map_size;
+  int unrolled_insn_copies = 0;
+  rtx test_reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
+  int insn_count = count_insns_in_loop (loop);
+
+  addr_placeholder = gen_reg_rtx (Pmode);
+
+  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;
+    }
+
+  /* Determine how BIVS are initialised by looking through pre-header
+     extended basic block.  */
+  loop_bivs_init_find (loop);
+
+  /* Look at the each biv and see if we can say anything better about its
+     initial value from any initializing insns set up above.  */
+  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.  */
+  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
+     so that "decrement and branch until zero" insn can be used.  */
+  check_dbra_loop (loop, insn_count);
+
+  /* Create reg_map to hold substitutions for replaceable giv regs.
+     Some givs might have been made from biv increments, so look at
+     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 = ivs->list; bl; bl = bl->next)
+    {
+      struct induction *v;
+      int benefit;
+      
+      /* Test whether it will be possible to eliminate this biv
+        provided all givs are reduced.  */
+      bl->eliminable = loop_biv_eliminable_p (loop, bl, threshold, insn_count);
+
+      /* This will be true at the end, if all givs which depend on this
+        biv have been strength reduced.
+        We can't (currently) eliminate the biv unless this is so.  */
+      bl->all_reduced = 1;
+
+      /* Check each extension 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 (regs, bl);
 
       for (v = bl->giv; v; v = v->next_iv)
        {
-         if (v->same && v->same->ignore)
-           v->ignore = 1;
+         struct induction *tv;
 
-         if (v->ignore)
+         if (v->ignore || v->same)
            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;
+         benefit = loop_giv_reduce_benefit (loop, bl, v, test_reg);
 
-             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 an insn is not to be strength reduced, then set its ignore
+            flag, and clear bl->all_reduced.  */
 
-             if (align == 0 || GET_CODE (v->mult_val) != CONST_INT
-                 || INTVAL (v->mult_val) % (align / BITS_PER_UNIT) != 0)
-               align = 0;
+         /* 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
+            value after the loop exit.  To make it simple, just reduce all
+            of such giv's whether or not we know they are used after the loop
+            exit.  */
 
-             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)
+         if (! flag_reduce_all_givs
+             && v->lifetime * threshold * benefit < insn_count
+             && ! bl->reversed)
            {
-             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
+             if (loop_dump_stream)
+               fprintf (loop_dump_stream,
+                        "giv of insn %d not worth while, %d vs %d.\n",
+                        INSN_UID (v->insn),
+                        v->lifetime * threshold * benefit, insn_count);
+             v->ignore = 1;
+             bl->all_reduced = 0;
            }
          else
            {
-             /* 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);
+             /* Check that we can increment the reduced giv without a
+                multiply insn.  If not, reject it.  */
+
+             for (tv = bl->biv; tv; tv = tv->next_iv)
+               if (tv->mult_val == const1_rtx
+                   && ! product_cheap_p (tv->add_val, v->mult_val))
+                 {
+                   if (loop_dump_stream)
+                     fprintf (loop_dump_stream,
+                              "giv of insn %d: would need a multiply.\n",
+                              INSN_UID (v->insn));
+                   v->ignore = 1;
+                   bl->all_reduced = 0;
+                   break;
+                 }
            }
+       }
 
-         /* When a loop is reversed, givs which depend on the reversed
-            biv, and which are live outside the loop, must be set to their
-            correct final value.  This insn is only needed if the giv is
-            not replaceable.  The correct final value is the same as the
-            value that the giv starts the reversed loop with.  */
-         if (bl->reversed && ! v->replaceable)
-           emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value),
-                             v->mult_val, v->add_val, v->dest_reg,
-                             end_insert_before);
-         else if (v->final_value)
-           {
-             rtx insert_before;
+      /* 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.  */
+      loop_givs_dead_check (loop, bl);
 
-             /* 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);
+      /* Reduce each giv that we decided to reduce.  */
+      loop_givs_reduce (loop, bl);
 
-#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
-           }
+      /* Rescan all givs.  If a giv is the same as a giv not reduced, mark it
+        as not reduced.
 
-         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");
-           }
-       }
+        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);
 
       /* All the givs based on the biv bl have been reduced if they
         merit it.  */
@@ -4320,23 +4393,23 @@ strength_reduce (loop, insn_count, flags)
         v->new_reg will either be or refer to the register of the giv it
         combined with.
 
-        Doing this clearing avoids problems in biv elimination where a
-        giv's new_reg is a complex value that can't be put in the insn but
-        the giv combined with (with a reg as new_reg) is marked maybe_dead.
-        Since the register will be used in either case, we'd prefer it be
-        used from the simpler giv.  */
+        Doing this clearing avoids problems in biv elimination where
+        a giv's new_reg is a complex value that can't be put in the
+        insn but the giv combined with (with a reg as new_reg) is
+        marked maybe_dead.  Since the register will be used in either
+        case, we'd prefer it be used from the simpler giv.  */
 
       for (v = bl->giv; v; v = v->next_iv)
        if (! v->maybe_dead && v->same)
          v->same->maybe_dead = 0;
 
       /* Try to eliminate the biv, if it is a candidate.
-        This won't work if ! all_reduced,
+        This won't work if ! bl->all_reduced,
         since the givs we planned to use might not have been reduced.
 
-        We have to be careful that we didn't initially think we could eliminate
-        this biv because of a giv that we now think may be dead and shouldn't
-        be used as a biv replacement.
+        We have to be careful that we didn't initially think we could
+        eliminate this biv because of a giv that we now think may be
+        dead and shouldn't be used as a biv replacement.
 
         Also, there is the possibility that we may have a giv that looks
         like it can be used to eliminate a biv, but the resulting insn
@@ -4348,7 +4421,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,
@@ -4363,35 +4436,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",
@@ -4402,7 +4449,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)
       {
@@ -4445,43 +4492,29 @@ 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)
     doloop_optimize (loop);
 #endif  /* HAVE_doloop_end  */
 
+  /* In case number of iterations is known, drop branch prediction note
+     in the branch.  Do that only in second loop pass, as loop unrolling
+     may change the number of iterations performed.  */
+  if ((flags & LOOP_BCT)
+      && loop_info->n_iterations / loop_info->unroll_number > 1)
+    {
+      int n = loop_info->n_iterations / loop_info->unroll_number - 1;
+      predict_insn (PREV_INSN (loop->end),
+                   PRED_LOOP_ITERATIONS,
+                   REG_BR_PROB_BASE - REG_BR_PROB_BASE / n);
+    }
+
   if (loop_dump_stream)
     fprintf (loop_dump_stream, "\n");
 
-egress:
-  VARRAY_FREE (ivs->reg_iv_type);
-  VARRAY_FREE (ivs->reg_iv_info);
-  free (ivs->reg_biv_class);
-  {
-    struct iv_class *iv = ivs->loop_iv_list;
-
-    while (iv) {
-      struct iv_class *next = iv->next;
-      struct induction *induction;
-      struct induction *next_induction;
-
-      for (induction = iv->biv; induction; induction = next_induction)
-       {
-         next_induction = induction->next_iv;
-         free (induction);
-       }
-      for (induction = iv->giv; induction; induction = next_induction)
-       {
-         next_induction = induction->next_iv;
-         free (induction);
-       }
-
-      free (iv);
-      iv = next;
-    }
-  }
+  loop_ivs_free (loop);
   if (reg_map)
     free (reg_map);
 }
@@ -4525,7 +4558,7 @@ check_insn_for_bivs (loop, p, not_every_iteration, maybe_multiple)
                          not_every_iteration, maybe_multiple);
              REG_IV_TYPE (ivs, REGNO (dest_reg)) = BASIC_INDUCT;
            }
-         else if (REGNO (dest_reg) < max_reg_before_loop)
+         else if (REGNO (dest_reg) < ivs->n_regs)
            REG_IV_TYPE (ivs, REGNO (dest_reg)) = NOT_BASIC_INDUCT;
        }
     }
@@ -4549,7 +4582,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
   if (GET_CODE (p) == INSN
       && (set = single_set (p))
       && GET_CODE (SET_DEST (set)) == REG
-      && ! VARRAY_CHAR (regs->may_not_optimize, REGNO (SET_DEST (set))))
+      && ! regs->array[REGNO (SET_DEST (set))].may_not_optimize)
     {
       rtx src_reg;
       rtx dest_reg;
@@ -4578,7 +4611,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
          /* Don't recognize a BASIC_INDUCT_VAR here.  */
          && dest_reg != src_reg
          /* This must be the only place where the register is set.  */
-         && (VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) == 1
+         && (regs->array[REGNO (dest_reg)].n_times_set == 1
              /* or all sets must be consecutive and make a giv.  */
              || (benefit = consec_sets_giv (loop, benefit, p,
                                             src_reg, dest_reg,
@@ -4593,12 +4626,12 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
            benefit += libcall_benefit (p);
 
          /* Skip the consecutive insns, if there are any.  */
-         if (VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) != 1)
+         if (regs->array[REGNO (dest_reg)].n_times_set != 1)
            p = last_consec_insn;
 
          record_giv (loop, v, p, src_reg, dest_reg, mult_val, add_val,
                      ext_val, benefit, DEST_REG, not_every_iteration,
-                     maybe_multiple, NULL_PTR);
+                     maybe_multiple, (rtx*)0);
 
        }
     }
@@ -4721,7 +4754,7 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
                        add_val, ext_val, benefit, DEST_ADDR,
                        not_every_iteration, maybe_multiple, &XEXP (x, 0));
 
-           v->mem_mode = GET_MODE (x);
+           v->mem = x;
          }
       }
       return;
@@ -4790,7 +4823,7 @@ record_biv (loop, 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 = ivs->reg_biv_class[REGNO (dest_reg)];
+  bl = REG_IV_CLASS (ivs, REGNO (dest_reg));
   if (bl == 0)
     {
       /* Create and initialize new iv_class.  */
@@ -4805,6 +4838,7 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
 
       /* Set initial value to the reg itself.  */
       bl->initial_value = dest_reg;
+      bl->final_value = 0;
       /* We haven't seen the initializing insn yet */
       bl->init_insn = 0;
       bl->init_set = 0;
@@ -4815,12 +4849,12 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
       bl->reversed = 0;
       bl->total_benefit = 0;
 
-      /* Add this class to ivs->loop_iv_list.  */
-      bl->next = ivs->loop_iv_list;
-      ivs->loop_iv_list = bl;
+      /* Add this class to ivs->list.  */
+      bl->next = ivs->list;
+      ivs->list = bl;
 
       /* Put it in the array of biv register classes.  */
-      ivs->reg_biv_class[REGNO (dest_reg)] = bl;
+      REG_IV_CLASS (ivs, REGNO (dest_reg)) = bl;
     }
 
   /* Update IV_CLASS entry for this biv.  */
@@ -4831,23 +4865,7 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
     bl->incremented = 1;
 
   if (loop_dump_stream)
-    {
-      fprintf (loop_dump_stream,
-              "Insn %d: possible biv, reg %d,",
-              INSN_UID (insn), REGNO (dest_reg));
-      if (GET_CODE (inc_val) == CONST_INT)
-       {
-         fprintf (loop_dump_stream, " const =");
-         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (inc_val));
-         fputc ('\n', loop_dump_stream);
-       }
-      else
-       {
-         fprintf (loop_dump_stream, " const = ");
-         print_rtl (loop_dump_stream, inc_val);
-         fprintf (loop_dump_stream, "\n");
-       }
-    }
+    loop_biv_dump (v, loop_dump_stream, 0);
 }
 \f
 /* Fill in the data about one giv.
@@ -4935,8 +4953,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
     {
       v->mode = GET_MODE (SET_DEST (set));
 
-      v->lifetime = (uid_luid[REGNO_LAST_UID (REGNO (dest_reg))]
-                    - uid_luid[REGNO_FIRST_UID (REGNO (dest_reg))]);
+      v->lifetime = LOOP_REG_LIFETIME (loop, REGNO (dest_reg));
 
       /* If the lifetime is zero, it means that this register is
         really a dead store.  So mark this as a giv that can be
@@ -4950,7 +4967,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
 
   /* Add the giv to the class of givs computed from one biv.  */
 
-  bl = ivs->reg_biv_class[REGNO (src_reg)];
+  bl = REG_IV_CLASS (ivs, REGNO (src_reg));
   if (bl)
     {
       v->next_iv = bl->giv;
@@ -4981,7 +4998,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
 
       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)))
@@ -5004,10 +5021,10 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
          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;
@@ -5062,69 +5079,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
   }
 
   if (loop_dump_stream)
-    {
-      if (type == DEST_REG)
-       fprintf (loop_dump_stream, "Insn %d: giv reg %d",
-                INSN_UID (insn), REGNO (dest_reg));
-      else
-       fprintf (loop_dump_stream, "Insn %d: dest address",
-                INSN_UID (insn));
-
-      fprintf (loop_dump_stream, " src reg %d benefit %d",
-              REGNO (src_reg), v->benefit);
-      fprintf (loop_dump_stream, " lifetime %d",
-              v->lifetime);
-
-      if (v->replaceable)
-       fprintf (loop_dump_stream, " replaceable");
-
-      if (v->no_const_addval)
-       fprintf (loop_dump_stream, " ncav");
-
-      if (v->ext_dependant)
-       {
-         switch (GET_CODE (v->ext_dependant))
-           {
-           case SIGN_EXTEND:
-             fprintf (loop_dump_stream, " ext se");
-             break;
-           case ZERO_EXTEND:
-             fprintf (loop_dump_stream, " ext ze");
-             break;
-           case TRUNCATE:
-             fprintf (loop_dump_stream, " ext tr");
-             break;
-           default:
-             abort ();
-           }
-       }
-
-      if (GET_CODE (mult_val) == CONST_INT)
-       {
-         fprintf (loop_dump_stream, " mult ");
-         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (mult_val));
-       }
-      else
-       {
-         fprintf (loop_dump_stream, " mult ");
-         print_rtl (loop_dump_stream, mult_val);
-       }
-
-      if (GET_CODE (add_val) == CONST_INT)
-       {
-         fprintf (loop_dump_stream, " add ");
-         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (add_val));
-       }
-      else
-       {
-         fprintf (loop_dump_stream, " add ");
-         print_rtl (loop_dump_stream, add_val);
-       }
-    }
-
-  if (loop_dump_stream)
-    fprintf (loop_dump_stream, "\n");
-
+    loop_giv_dump (v, loop_dump_stream, 0);
 }
 
 /* All this does is determine whether a giv can be made replaceable because
@@ -5142,7 +5097,7 @@ check_final_value (loop, v)
   struct iv_class *bl;
   rtx final_value = 0;
 
-  bl = ivs->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.  */
@@ -5323,7 +5278,7 @@ update_giv_derive (loop, p)
      subsequent biv update was performed.  If this adjustment cannot be done,
      the giv cannot derive further givs.  */
 
-  for (bl = ivs->loop_iv_list; bl; bl = bl->next)
+  for (bl = ivs->list; bl; bl = bl->next)
     for (biv = bl->biv; biv; biv = biv->next_iv)
       if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
          || biv->insn == p)
@@ -5625,7 +5580,7 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
       /* Since this is now an invariant and wasn't before, it must be a giv
         with MULT_VAL == 0.  It doesn't matter which BIV we associate this
         with.  */
-      *src_reg = ivs->loop_iv_list->biv->dest_reg;
+      *src_reg = ivs->list->biv->dest_reg;
       *mult_val = const0_rtx;
       *add_val = x;
       break;
@@ -6001,7 +5956,7 @@ simplify_giv_expr (loop, x, ext_val, benefit)
               less harmful than reducing many givs that are not really
               beneficial.  */
            {
-             rtx single_use = VARRAY_RTX (regs->single_usage, REGNO (x));
+             rtx single_use = regs->array[REGNO (x)].single_usage;
              if (single_use && single_use != const0_rtx)
                *benefit += v->benefit;
            }
@@ -6245,7 +6200,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
   REG_IV_TYPE (ivs, REGNO (dest_reg)) = GENERAL_INDUCT;
   REG_IV_INFO (ivs, REGNO (dest_reg)) = v;
 
-  count = VARRAY_INT (regs->n_times_set, REGNO (dest_reg)) - 1;
+  count = regs->array[REGNO (dest_reg)].n_times_set - 1;
 
   while (count > 0)
     {
@@ -6527,7 +6482,7 @@ combine_givs_p (g1, g2)
      the expression of G2 in terms of G1 can be used.  */
   if (ret != NULL_RTX
       && g2->giv_type == DEST_ADDR
-      && memory_address_p (g2->mem_mode, ret)
+      && 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.  */
@@ -6558,7 +6513,8 @@ check_ext_dependant_givs (bl, loop_info)
   int ze_ok = 0, se_ok = 0, info_ok = 0;
   enum machine_mode biv_mode = GET_MODE (bl->biv->src_reg);
   HOST_WIDE_INT start_val;
-  unsigned HOST_WIDE_INT u_end_val, u_start_val;
+  unsigned HOST_WIDE_INT u_end_val = 0;
+  unsigned HOST_WIDE_INT u_start_val = 0;
   rtx incr = pc_rtx;
   struct induction *v;
 
@@ -6704,6 +6660,7 @@ check_ext_dependant_givs (bl, loop_info)
                         INSN_UID (v->insn), why);
              }
            v->ignore = 1;
+           bl->all_reduced = 0;
          }
       }
 }
@@ -6803,8 +6760,7 @@ combine_givs (regs, bl)
         DEST_ADDR targets on hosts with reg+reg addressing, though it can
         be seen elsewhere as well.  */
       if (g1->giv_type == DEST_REG
-         && (single_use = VARRAY_RTX (regs->single_usage,
-                                      REGNO (g1->dest_reg)))
+         && (single_use = regs->array[REGNO (g1->dest_reg)].single_usage)
          && single_use != const0_rtx)
        continue;
 
@@ -6924,40 +6880,38 @@ restart:
   free (can_combine);
 }
 \f
-/* EMIT code before INSERT_BEFORE to set REG = B * M + A.  */
+/* Generate sequence for REG = B * M + A.  */
 
-void
-emit_iv_add_mult (b, m, a, reg, insert_before)
+static rtx
+gen_add_mult (b, m, a, reg)
      rtx b;          /* initial value of basic induction variable */
      rtx m;          /* multiplicative constant */
      rtx a;          /* additive constant */
      rtx reg;        /* destination register */
-     rtx insert_before;
 {
   rtx seq;
   rtx result;
 
-  /* Prevent unexpected sharing of these rtx.  */
-  a = copy_rtx (a);
-  b = copy_rtx (b);
-
-  /* Increase the lifetime of any invariants moved further in code.  */
-  update_reg_last_use (a, insert_before);
-  update_reg_last_use (b, insert_before);
-  update_reg_last_use (m, insert_before);
-
   start_sequence ();
+  /* Use unsigned arithmetic.  */
   result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 1);
   if (reg != result)
     emit_move_insn (reg, result);
   seq = gen_sequence ();
   end_sequence ();
 
-  emit_insn_before (seq, insert_before);
+  return seq;
+}
+
+
+/* Update registers created in insn sequence SEQ.  */
 
-  /* It is entirely possible that the expansion created lots of new
-     registers.  Iterate over the sequence we just created and
-     record them all.  */
+static void
+loop_regs_update (loop, seq)
+     const struct loop *loop ATTRIBUTE_UNUSED;
+     rtx seq;
+{
+  /* Update register info for alias analysis.  */
 
   if (GET_CODE (seq) == SEQUENCE)
     {
@@ -6969,13 +6923,107 @@ 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 emit_iv_add_mult, but compute cost rather than emitting
-   insns.  */
+
+
+/* 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 */
@@ -6987,7 +7035,7 @@ iv_add_mult_cost (b, m, a, reg)
   rtx last, result;
 
   start_sequence ();
-  result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 0);
+  result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 1);
   if (reg != result)
     emit_move_insn (reg, result);
   last = get_last_insn ();
@@ -7146,7 +7194,7 @@ check_dbra_loop (loop, insn_count)
      it will be zero on the last iteration.  Also skip if the biv is
      used between its update and the test insn.  */
 
-  for (bl = ivs->loop_iv_list; bl; bl = bl->next)
+  for (bl = ivs->list; bl; bl = bl->next)
     {
       if (bl->biv_count == 1
          && ! bl->biv->maybe_multiple
@@ -7241,6 +7289,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
@@ -7277,6 +7326,14 @@ 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)
@@ -7298,12 +7355,11 @@ check_dbra_loop (loop, insn_count)
            {
              struct induction *v;
 
-             reversible_mem_store
-               = (! loop_info->unknown_address_altered
-                  && ! loop_info->unknown_constant_address_altered
-                  && ! loop_invariant_p (loop,
-                                         XEXP (XEXP (loop_info->store_mems, 0),
-                                               0)));
+             /* If we could prove that each of the memory locations
+                written to was different, then we could reverse the
+                store -- but we don't presently have any way of
+                knowing that.  */
+             reversible_mem_store = 0;
 
              /* If the store depends on a register that is set after the
                 store, it depends on the initial value, and is thus not
@@ -7331,12 +7387,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 + loop_info->num_mem_sets
-              + LOOP_MOVABLES (loop)->num + compare_and_branch == insn_count)
-          && (bl == ivs->loop_iv_list && bl->next == 0))
+              + num_unmoved_movables (loop) + compare_and_branch == insn_count)
+          && (bl == ivs->list && bl->next == 0))
          || no_use_except_counting)
        {
          rtx tem;
@@ -7497,8 +7553,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)
                {
@@ -7515,9 +7570,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));
@@ -7535,9 +7589,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
@@ -7551,7 +7605,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.  */
@@ -7577,8 +7631,7 @@ check_dbra_loop (loop, insn_count)
              if ((REGNO_LAST_UID (bl->regno) != INSN_UID (first_compare))
                  || ! bl->init_insn
                  || REGNO_FIRST_UID (bl->regno) != INSN_UID (bl->init_insn))
-               emit_insn_after (gen_move_insn (reg, final_value),
-                                loop_end);
+               loop_insn_sink (loop, gen_move_insn (reg, final_value));
 
              /* Delete compare/branch at end of loop.  */
              delete_insn (PREV_INSN (loop_end));
@@ -7635,7 +7688,7 @@ check_dbra_loop (loop, insn_count)
                       REG_EQUAL notes should still be correct.  */
                    if (! set
                        || GET_CODE (SET_DEST (set)) != REG
-                       || (size_t) REGNO (SET_DEST (set)) >= ivs->reg_iv_type->num_elements
+                       || (size_t) REGNO (SET_DEST (set)) >= ivs->n_regs
                        || REG_IV_TYPE (ivs, REGNO (SET_DEST (set))) != GENERAL_INDUCT
                        || REG_IV_INFO (ivs, REGNO (SET_DEST (set)))->src_reg != bl->biv->src_reg)
                      for (pnote = &REG_NOTES (p); *pnote;)
@@ -7690,17 +7743,16 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   rtx reg = bl->biv->dest_reg;
-  rtx loop_start = loop->start;
-  rtx loop_end = loop->end;
   rtx p;
 
   /* Scan all insns in the loop, stopping if we find one that uses the
      biv in a way that we cannot eliminate.  */
 
-  for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
+  for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
     {
       enum rtx_code code = GET_CODE (p);
-      rtx where = threshold >= insn_count ? loop_start : p;
+      basic_block where_bb = 0;
+      rtx where_insn = threshold >= insn_count ? 0 : p;
 
       /* If this is a libcall that sets a giv, skip ahead to its end.  */
       if (GET_RTX_CLASS (code) == 'i')
@@ -7716,7 +7768,7 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
                {
                  unsigned int regno = REGNO (SET_DEST (set));
 
-                 if (regno < max_reg_before_loop
+                 if (regno < ivs->n_regs
                      && REG_IV_TYPE (ivs, regno) == GENERAL_INDUCT
                      && REG_IV_INFO (ivs, regno)->src_reg == bl->biv->src_reg)
                    p = last;
@@ -7726,7 +7778,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,
@@ -7736,7 +7788,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",
@@ -7808,18 +7860,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;
@@ -7929,8 +7983,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.  */
@@ -7996,7 +8051,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 ())
@@ -8029,7 +8086,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 ())
@@ -8065,8 +8124,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;
@@ -8100,7 +8160,8 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where)
              if (v->ignore || v->maybe_dead || v->mode != mode)
                continue;
 
-             for (tv = ivs->reg_biv_class[REGNO (arg)]->giv; tv; tv = tv->next_iv)
+             for (tv = REG_IV_CLASS (ivs, REGNO (arg))->giv; tv; 
+                  tv = tv->next_iv)
                if (! tv->ignore && ! tv->maybe_dead
                    && rtx_equal_p (tv->mult_val, v->mult_val)
                    && rtx_equal_p (tv->add_val, v->add_val)
@@ -8146,14 +8207,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;
        }
@@ -8194,11 +8255,11 @@ record_initial (dest, set, data)
   struct iv_class *bl;
 
   if (GET_CODE (dest) != REG
-      || REGNO (dest) >= max_reg_before_loop
+      || REGNO (dest) >= ivs->n_regs
       || REG_IV_TYPE (ivs, REGNO (dest)) != BASIC_INDUCT)
     return;
 
-  bl = ivs->reg_biv_class[REGNO (dest)];
+  bl = REG_IV_CLASS (ivs, REGNO (dest));
 
   /* If this is the first set found, record it.  */
   if (bl->init_insn == 0)
@@ -8211,7 +8272,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)
@@ -8221,11 +8282,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;
@@ -8278,7 +8343,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);
@@ -8287,10 +8351,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;
@@ -8341,13 +8404,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));
 
@@ -8407,10 +8476,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);
            }
@@ -8428,10 +8493,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;
            }
 
@@ -8494,15 +8558,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)
@@ -8556,7 +8611,7 @@ get_condition_for_loop (loop, x)
      const struct loop *loop;
      rtx x;
 {
-  rtx comparison = get_condition (x, NULL_PTR);
+  rtx comparison = get_condition (x, (rtx*)0);
 
   if (comparison == 0
       || ! loop_invariant_p (loop, XEXP (comparison, 0))
@@ -8662,65 +8717,126 @@ insert_loop_mem (mem, data)
   return 0;
 }
 
-/* Like load_mems, but also ensures that REGS->SET_IN_LOOP,
-   REGS->MAY_NOT_OPTIMIZE, REGS->SINGLE_USAGE, and INSN_COUNT have the correct
-   values after load_mems.  */
+
+/* Allocate REGS->ARRAY or reallocate it if it is too small.
+
+   Increment REGS->ARRAY[I].SET_IN_LOOP at the index I of each
+   register that is modified by an insn between FROM and TO.  If the
+   value of an element of REGS->array[I].SET_IN_LOOP becomes 127 or
+   more, stop incrementing it, to avoid overflow.
+
+   Store in REGS->ARRAY[I].SINGLE_USAGE the single insn in which
+   register I is used, if it is only used once.  Otherwise, it is set
+   to 0 (for no uses) or const0_rtx for more than one use.  This
+   parameter may be zero, in which case this processing is not done.
+
+   Set REGS->ARRAY[I].MAY_NOT_OPTIMIZE nonzero if we should not
+   optimize register I.  */
 
 static void
-load_mems_and_recount_loop_regs_set (loop, insn_count)
+loop_regs_scan (loop, extra_size)
      const struct loop *loop;
-     int *insn_count;
+     int extra_size;
 {
   struct loop_regs *regs = LOOP_REGS (loop);
-  int nregs = max_reg_num ();
+  int old_nregs;
+  /* last_set[n] is nonzero iff reg n has been set in the current
+   basic block.  In that case, it is the insn that last set reg n.  */
+  rtx *last_set;
+  rtx insn;
+  int i;
 
-  load_mems (loop);
+  old_nregs = regs->num;
+  regs->num = max_reg_num ();
 
-  /* Recalculate regs->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;
+    }
 
-      old_nregs = nregs;
-      nregs = max_reg_num ();
+  last_set = (rtx *) xcalloc (regs->num, sizeof (rtx));
 
-      if ((unsigned) nregs > regs->set_in_loop->num_elements)
+  /* Scan the loop, recording register usage.  */
+  for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
+       insn = NEXT_INSN (insn))
+    {
+      if (INSN_P (insn))
        {
-         /* Grow all the arrays.  */
-         VARRAY_GROW (regs->set_in_loop, nregs);
-         VARRAY_GROW (regs->n_times_set, nregs);
-         VARRAY_GROW (regs->may_not_optimize, nregs);
-         VARRAY_GROW (regs->single_usage, nregs);
-       }
-      /* Clear the arrays */
-      memset ((char *) &regs->set_in_loop->data, 0, nregs * sizeof (int));
-      memset ((char *) &regs->may_not_optimize->data, 0, nregs * sizeof (char));
-      memset ((char *) &regs->single_usage->data, 0, nregs * sizeof (rtx));
+         /* Record registers that have exactly one use.  */
+         find_single_use_in_loop (regs, insn, PATTERN (insn));
 
-      count_loop_regs_set (loop, regs->may_not_optimize, regs->single_usage,
-                          insn_count, nregs);
+         /* Include uses in REG_EQUAL notes.  */
+         if (REG_NOTES (insn))
+           find_single_use_in_loop (regs, insn, REG_NOTES (insn));
 
-      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-       {
-         VARRAY_CHAR (regs->may_not_optimize, i) = 1;
-         VARRAY_INT (regs->set_in_loop, i) = 1;
+         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);
+           }
        }
 
+      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++)
+    {
+      regs->array[i].may_not_optimize = 1;
+      regs->array[i].set_in_loop = 1;
+    }
+
 #ifdef AVOID_CCMODE_COPIES
-      /* Don't try to move insns which set CC registers if we should not
-        create CCmode register copies.  */
-      for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
-       if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
-         VARRAY_CHAR (regs->may_not_optimize, i) = 1;
+  /* Don't try to move insns which set CC registers if we should not
+     create CCmode register copies.  */
+  for (i = regs->num - 1; i >= FIRST_PSEUDO_REGISTER; i--)
+    if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
+      regs->array[i].may_not_optimize = 1;
 #endif
+  
+  /* Set regs->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 regs->n_times_set for the new registers.  */
-      bcopy ((char *) (&regs->set_in_loop->data.i[0] + old_nregs),
-            (char *) (&regs->n_times_set->data.i[0] + old_nregs),
-            (nregs - old_nregs) * sizeof (int));
-    }
+  free (last_set);
+}
+
+/* Returns the number of real INSNs in the LOOP.  */
+
+static int
+count_insns_in_loop (loop)
+     const struct loop *loop;
+{
+  int count = 0;
+  rtx insn;
+
+  for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
+       insn = NEXT_INSN (insn))
+    if (INSN_P (insn))
+      ++count;
+
+  return count;
 }
 
 /* Move MEMs into registers for the duration of the loop.  */
@@ -8733,12 +8849,12 @@ load_mems (loop)
   struct loop_regs *regs = LOOP_REGS (loop);
   int maybe_never = 0;
   int i;
-  rtx p;
+  rtx p, prev_ebb_head;
   rtx label = NULL_RTX;
   rtx end_label;
   /* Nonzero if the next instruction may never be executed.  */
   int next_maybe_never = 0;
-  int last_max_reg = max_reg_num ();
+  unsigned int last_max_reg = max_reg_num ();
 
   if (loop_info->mems_idx == 0)
     return;
@@ -8752,7 +8868,7 @@ load_mems (loop)
      never executed.  Also check if there is a goto out of the loop other
      than right after the end of the loop.  */
   for (p = next_insn_in_loop (loop, loop->scan_start);
-       p != NULL_RTX && ! maybe_never;
+       p != NULL_RTX;
        p = next_insn_in_loop (loop, p))
     {
       if (GET_CODE (p) == CODE_LABEL)
@@ -8772,10 +8888,13 @@ load_mems (loop)
          /* If this is a jump outside of the loop but not right
             after the end of the loop, we would have to emit new fixup
             sequences for each such label.  */
-         if (JUMP_LABEL (p) != end_label
-             && (INSN_UID (JUMP_LABEL (p)) >= max_uid_for_loop
-                 || INSN_LUID (JUMP_LABEL (p)) < INSN_LUID (loop->start)
-                 || INSN_LUID (JUMP_LABEL (p)) > INSN_LUID (loop->end)))
+         if (/* If we can't tell where control might go when this
+                JUMP_INSN is executed, we must be conservative.  */
+             !JUMP_LABEL (p)
+             || (JUMP_LABEL (p) != end_label
+                 && (INSN_UID (JUMP_LABEL (p)) >= max_uid_for_loop
+                     || INSN_LUID (JUMP_LABEL (p)) < INSN_LUID (loop->start)
+                     || INSN_LUID (JUMP_LABEL (p)) > INSN_LUID (loop->end))))
            return;
 
          if (!any_condjump_p (p))
@@ -8795,6 +8914,7 @@ load_mems (loop)
        PREV_INSN (p) && GET_CODE (p) != CODE_LABEL;
        p = PREV_INSN (p))
     ;
+  prev_ebb_head = p;
 
   cselib_init ();
 
@@ -8885,7 +9005,7 @@ load_mems (loop)
       loop_info->mems[i].reg = reg;
 
       /* Now, replace all references to the MEM with the
-        corresponding pesudos.  */
+        corresponding pseudos.  */
       maybe_never = 0;
       for (p = next_insn_in_loop (loop, loop->scan_start);
           p != NULL_RTX;
@@ -8906,8 +9026,7 @@ load_mems (loop)
                  && GET_CODE (SET_DEST (set)) == REG
                  && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
                  && REGNO (SET_DEST (set)) < last_max_reg
-                 && VARRAY_INT (regs->n_times_set,
-                                REGNO (SET_DEST (set))) == 1
+                 && regs->array[REGNO (SET_DEST (set))].n_times_set == 1
                  && rtx_equal_p (SET_SRC (set), mem))
                SET_REGNO_REG_SET (&load_copies, REGNO (SET_DEST (set)));
 
@@ -8921,7 +9040,7 @@ load_mems (loop)
                  && GET_CODE (SET_SRC (set)) == REG
                  && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER
                  && REGNO (SET_SRC (set)) < last_max_reg
-                 && VARRAY_INT (regs->n_times_set, REGNO (SET_SRC (set))) == 1
+                 && regs->array[REGNO (SET_SRC (set))].n_times_set == 1
                  && rtx_equal_p (SET_DEST (set), mem))
                SET_REGNO_REG_SET (&store_copies, REGNO (SET_SRC (set)));
 
@@ -8957,7 +9076,7 @@ load_mems (loop)
                  if (CONSTANT_P (equiv->loc))
                    const_equiv = equiv;
                  else if (GET_CODE (equiv->loc) == REG
-                          /* Extending hard register lifetimes cuases crash
+                          /* Extending hard register lifetimes causes crash
                              on SRC targets.  Doing so on non-SRC is
                              probably also not good idea, since we most
                              probably have pseudoregister equivalence as
@@ -8983,8 +9102,19 @@ load_mems (loop)
              if (best_equiv)
                best = copy_rtx (best_equiv->loc);
            }
+
          set = gen_move_insn (reg, best);
-         set = emit_insn_before (set, loop->start);
+         set = loop_insn_hoist (loop, set);
+         if (REG_P (best))
+           {
+             for (p = prev_ebb_head; p != loop->start; p = NEXT_INSN (p))
+               if (REGNO_LAST_UID (REGNO (best)) == INSN_UID (p))
+                 {
+                   REGNO_LAST_UID (REGNO (best)) = INSN_UID (set);
+                   break;
+                 }
+           }
+
          if (const_equiv)
            REG_NOTES (set) = gen_rtx_EXPR_LIST (REG_EQUAL,
                                                 copy_rtx (const_equiv->loc),
@@ -9001,7 +9131,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)
@@ -9148,17 +9278,52 @@ try_copy_prop (loop, replacement, regno)
        fprintf (loop_dump_stream, "  Replaced reg %d", regno);
       if (store_is_first && replaced_last)
        {
-         PUT_CODE (init_insn, NOTE);
-         NOTE_LINE_NUMBER (init_insn) = NOTE_INSN_DELETED;
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream, ", deleting init_insn (%d)",
-                    INSN_UID (init_insn));
+         rtx first;
+         rtx retval_note;
+
+         /* Assume we're just deleting INIT_INSN.  */
+         first = init_insn;
+         /* Look for REG_RETVAL note.  If we're deleting the end of
+            the libcall sequence, the whole sequence can go.  */
+         retval_note = find_reg_note (init_insn, REG_RETVAL, NULL_RTX);
+         /* If we found a REG_RETVAL note, find the first instruction
+            in the sequence.  */
+         if (retval_note)
+           first = XEXP (retval_note, 0);
+
+         /* Delete the instructions.  */
+         loop_delete_insns (first, init_insn);
        }
       if (loop_dump_stream)
        fprintf (loop_dump_stream, ".\n");
     }
 }
 
+/* Replace all the instructions from FIRST up to and including LAST
+   with NOTE_INSN_DELETED notes.  */
+
+static void
+loop_delete_insns (first, last)
+     rtx first;
+     rtx last;
+{
+  while (1)
+    {
+      PUT_CODE (first, NOTE);
+      NOTE_LINE_NUMBER (first) = NOTE_INSN_DELETED;
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream, ", deleting init_insn (%d)",
+                INSN_UID (first));
+
+      /* If this was the LAST instructions we're supposed to delete,
+        we're done.  */
+      if (first == last)
+       break;
+
+      first = NEXT_INSN (first);
+    }
+}
+
 /* Try to replace occurrences of pseudo REGNO with REPLACEMENT within
    loop LOOP if the order of the sets of these registers can be
    swapped.  There must be exactly one insn within the loop that sets
@@ -9171,7 +9336,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);
@@ -9181,7 +9346,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
@@ -9201,7 +9366,7 @@ try_swap_copy_prop (loop, replacement, regno)
 
       prev_insn = PREV_INSN (insn);
 
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+      if (INSN_P (insn)
          && (prev_set = single_set (prev_insn))
          && GET_CODE (SET_DEST (prev_set)) == REG
          && REGNO (SET_DEST (prev_set)) == regno)
@@ -9367,6 +9532,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)