OSDN Git Service

* unroll.c (copy_loop_body): Always ensure at least two insns
[pf3gnuchains/gcc-fork.git] / gcc / unroll.c
index 214e948..9c0109d 100644 (file)
@@ -1,5 +1,5 @@
 /* Try to unroll loops, and split induction variables.
-   Copyright (C) 1992, 93, 94, 95, 97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1992, 93, 94, 95, 97, 98, 1999 Free Software Foundation, Inc.
    Contributed by James E. Wilson, Cygnus Support/UC Berkeley.
 
 This file is part of GNU CC.
@@ -99,11 +99,11 @@ Boston, MA 02111-1307, USA.  */
        int iterations = (len + 1) >> 1;
        int i;
        for (p; p < q; p++, q--;)
-         {
-           tmp = *q;
-           *q = *p;
-           *p = tmp;
-         }
+        {
+          tmp = *q;
+          *q = *p;
+          *p = tmp;
+        }
      }
    Note that:
      start value = p = &buffer + current_iteration
@@ -141,7 +141,7 @@ Boston, MA 02111-1307, USA.  */
 
 struct _factor { int factor, count; } factors[NUM_FACTORS]
   = { {2, 0}, {3, 0}, {5, 0}, {7, 0}};
-      
+
 /* Describes the different types of loop unrolling performed.  */
 
 enum unroll_types { UNROLL_COMPLETELY, UNROLL_MODULO, UNROLL_NAIVE };
@@ -180,6 +180,10 @@ static struct induction **addr_combined_regs;
 static rtx *splittable_regs;
 
 /* Indexed by register number, if this is a splittable induction variable,
+   this indicates if it was made from a derived giv.  */
+static char *derived_regs;
+
+/* Indexed by register number, if this is a splittable induction variable,
    then this will hold the number of instructions in the loop that modify
    the induction variable.  Used to ensure that only the last insn modifying
    a split iv will update the original iv of the dest.  */
@@ -234,8 +238,8 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   struct inline_remap *map;
   char *local_label;
   char *local_regno;
+  int max_local_regnum;
   int maxregnum;
-  int new_maxregnum;
   rtx exit_label = 0;
   rtx start_label;
   struct iv_class *bl;
@@ -306,7 +310,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   if (loop_dump_stream && loop_info->n_iterations > 0)
     {
       fputs ("Loop unrolling: ", loop_dump_stream);
-      fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, 
+      fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC,
               loop_info->n_iterations);
       fputs (" iterations.\n", loop_dump_stream);
     }
@@ -680,6 +684,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   map = (struct inline_remap *) alloca (sizeof (struct inline_remap));
 
   map->integrating = 0;
+  map->const_equiv_varray = 0;
 
   /* Allocate the label map.  */
 
@@ -751,6 +756,9 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   /* The preconditioning code may allocate two new pseudo registers.  */
   maxregnum = max_reg_num ();
 
+  /* local_regno is only valid for regnos < max_local_regnum.  */
+  max_local_regnum = maxregnum;
+
   /* Allocate and zero out the splittable_regs and addr_combined_regs
      arrays.  These must be zeroed here because they will be used if
      loop preconditioning is performed, and must be zero for that case.
@@ -761,16 +769,15 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
   splittable_regs = (rtx *) alloca (maxregnum * sizeof (rtx));
   bzero ((char *) splittable_regs, maxregnum * sizeof (rtx));
+  derived_regs = alloca (maxregnum);
+  bzero (derived_regs, maxregnum);
   splittable_regs_updates = (int *) alloca (maxregnum * sizeof (int));
   bzero ((char *) splittable_regs_updates, maxregnum * sizeof (int));
   addr_combined_regs
     = (struct induction **) alloca (maxregnum * sizeof (struct induction *));
   bzero ((char *) addr_combined_regs, maxregnum * sizeof (struct induction *));
-  /* We must limit it to max_reg_before_loop, because only these pseudo
-     registers have valid regno_first_uid info.  Any register created after
-     that is unlikely to be local to the loop anyways.  */
-  local_regno = (char *) alloca (max_reg_before_loop);
-  bzero (local_regno, max_reg_before_loop);
+  local_regno = (char *) alloca (maxregnum);
+  bzero (local_regno, maxregnum);
 
   /* Mark all local registers, i.e. the ones which are referenced only
      inside the loop.  */
@@ -793,6 +800,8 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
     /* If a pseudo's lifetime is entirely contained within this loop, then we
        can use a different pseudo in each unrolled copy of the loop.  This
        results in better code.  */
+    /* We must limit the generic test to max_reg_before_loop, because only
+       these pseudo registers have valid regno_first_uid info.  */
     for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; ++j)
       if (REGNO_FIRST_UID (j) > 0 && REGNO_FIRST_UID (j) <= max_uid_for_loop
          && uid_luid[REGNO_FIRST_UID (j)] >= copy_start_luid
@@ -821,6 +830,14 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
                         j);
            }
        }
+    /* Givs that have been created from multiple biv increments always have
+       local registers.  */
+    for (j = first_increment_giv; j <= last_increment_giv; j++)
+      {
+       local_regno[j] = 1;
+       if (loop_dump_stream)
+         fprintf (loop_dump_stream, "Marked reg %d as local\n", j);
+      }
   }
 
   /* If this loop requires exit tests when unrolled, check to see if we
@@ -860,12 +877,9 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
          map->reg_map = (rtx *) alloca (maxregnum * sizeof (rtx));
 
-         map->const_equiv_map = (rtx *) alloca (maxregnum * sizeof (rtx));
-         map->const_age_map = (unsigned *) alloca (maxregnum
-                                                   * sizeof (unsigned));
-         map->const_equiv_map_size = maxregnum;
-         global_const_equiv_map = map->const_equiv_map;
-         global_const_equiv_map_size = maxregnum;
+         VARRAY_CONST_EQUIV_INIT (map->const_equiv_varray, maxregnum,
+                                  "unroll_loop");
+         global_const_equiv_varray = map->const_equiv_varray;
 
          init_reg_map (map, maxregnum);
 
@@ -889,7 +903,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
          /* Calculate the difference between the final and initial values.
             Final value may be a (plus (reg x) (const_int 1)) rtx.
             Let the following cse pass simplify this if initial value is
-            a constant. 
+            a constant.
 
             We must copy the final and initial values here to avoid
             improperly shared rtl.  */
@@ -919,12 +933,9 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
          if (loop_info->comparison_code != NE)
            {
-             emit_cmp_insn (initial_value, final_value, neg_inc ? LE : GE,
-                            NULL_RTX, mode, 0, 0);
-             if (neg_inc)
-               emit_jump_insn (gen_ble (labels[1]));
-             else
-               emit_jump_insn (gen_bge (labels[1]));
+             emit_cmp_and_jump_insns (initial_value, final_value,
+                                      neg_inc ? LE : GE,
+                                      NULL_RTX, mode, 0, 0, labels[1]);
              JUMP_LABEL (get_last_insn ()) = labels[1];
              LABEL_NUSES (labels[1])++;
            }
@@ -965,15 +976,9 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
                  cmp_code = LE;
                }
 
-             emit_cmp_insn (diff, GEN_INT (abs_inc * cmp_const),
-                            cmp_code, NULL_RTX, mode, 0, 0);
-
-             if (i == 0)
-               emit_jump_insn (gen_beq (labels[i]));
-             else if (neg_inc)
-               emit_jump_insn (gen_bge (labels[i]));
-             else
-               emit_jump_insn (gen_ble (labels[i]));
+             emit_cmp_and_jump_insns (diff, GEN_INT (abs_inc * cmp_const),
+                                      cmp_code, NULL_RTX, mode, 0, 0,
+                                      labels[i]);
              JUMP_LABEL (get_last_insn ()) = labels[i];
              LABEL_NUSES (labels[i])++;
            }
@@ -986,7 +991,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
             For the negative increment case, the branch here could easily
             be merged with the `0' case branch above.  For the positive
             increment case, it is not clear how this can be simplified.  */
-            
+
          if (abs_inc != 1)
            {
              int cmp_const;
@@ -1003,13 +1008,8 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
                  cmp_code = GE;
                }
 
-             emit_cmp_insn (diff, GEN_INT (cmp_const), cmp_code, NULL_RTX,
-                            mode, 0, 0);
-
-             if (neg_inc)
-               emit_jump_insn (gen_ble (labels[0]));
-             else
-               emit_jump_insn (gen_bge (labels[0]));
+             emit_cmp_and_jump_insns (diff, GEN_INT (cmp_const), cmp_code,
+                                      NULL_RTX, mode, 0, 0, labels[0]);
              JUMP_LABEL (get_last_insn ()) = labels[0];
              LABEL_NUSES (labels[0])++;
            }
@@ -1017,7 +1017,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
          sequence = gen_sequence ();
          end_sequence ();
          emit_insn_before (sequence, loop_start);
-         
+
          /* Only the last copy of the loop body here needs the exit
             test, so set copy_end to exclude the compare/branch here,
             and then reset it inside the loop when get to the last
@@ -1046,16 +1046,16 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
                                PREV_INSN (loop_start));
 
              bzero ((char *) map->insn_map, max_insnno * sizeof (rtx));
-             bzero ((char *) map->const_equiv_map, maxregnum * sizeof (rtx));
-             bzero ((char *) map->const_age_map,
-                    maxregnum * sizeof (unsigned));
+             bzero ((char *) &VARRAY_CONST_EQUIV (map->const_equiv_varray, 0),
+                    (VARRAY_SIZE (map->const_equiv_varray)
+                     * sizeof (struct const_equiv_data)));
              map->const_age = 0;
 
              for (j = 0; j < max_labelno; j++)
                if (local_label[j])
                  set_label_in_map (map, j, gen_label_rtx ());
 
-             for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; j++)
+             for (j = FIRST_PSEUDO_REGISTER; j < max_local_regnum; j++)
                if (local_regno[j])
                  {
                    map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
@@ -1114,7 +1114,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream, "Unrolling failure: Naive unrolling not being done.\n");
-      return;
+      goto egress;
     }
 
   /* At this point, we are guaranteed to unroll the loop.  */
@@ -1150,19 +1150,11 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
   init_reg_map (map, maxregnum);
 
-  /* Space is needed in some of the map for new registers, so new_maxregnum
-     is an (over)estimate of how many registers will exist at the end.  */
-  new_maxregnum = maxregnum + (temp * unroll_number * 2);
-
-  /* Must realloc space for the constant maps, because the number of registers
-     may have changed.  */
-
-  map->const_equiv_map = (rtx *) alloca (new_maxregnum * sizeof (rtx));
-  map->const_age_map = (unsigned *) alloca (new_maxregnum * sizeof (unsigned));
-
-  map->const_equiv_map_size = new_maxregnum;
-  global_const_equiv_map = map->const_equiv_map;
-  global_const_equiv_map_size = new_maxregnum;
+  if (map->const_equiv_varray == 0)
+    VARRAY_CONST_EQUIV_INIT (map->const_equiv_varray,
+                            maxregnum + temp * unroll_number * 2,
+                            "unroll_loop");
+  global_const_equiv_varray = map->const_equiv_varray;
 
   /* Search the list of bivs and givs to find ones which need to be remapped
      when split, and set their reg_map entry appropriately.  */
@@ -1203,15 +1195,15 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   for (i = 0; i < unroll_number; i++)
     {
       bzero ((char *) map->insn_map, max_insnno * sizeof (rtx));
-      bzero ((char *) map->const_equiv_map, new_maxregnum * sizeof (rtx));
-      bzero ((char *) map->const_age_map, new_maxregnum * sizeof (unsigned));
+      bzero ((char *) &VARRAY_CONST_EQUIV (map->const_equiv_varray, 0),
+            VARRAY_SIZE (map->const_equiv_varray) * sizeof (struct const_equiv_data));
       map->const_age = 0;
 
       for (j = 0; j < max_labelno; j++)
        if (local_label[j])
          set_label_in_map (map, j, gen_label_rtx ());
 
-      for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; j++)
+      for (j = FIRST_PSEUDO_REGISTER; j < max_local_regnum; j++)
        if (local_regno[j])
          {
            map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
@@ -1225,7 +1217,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
        {
          insn = PREV_INSN (copy_start);
          pattern = PATTERN (insn);
-         
+
          tem = get_label_from_map (map,
                                    CODE_LABEL_NUMBER
                                    (XEXP (SET_SRC (pattern), 0)));
@@ -1256,7 +1248,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   else
     safety_label = emit_label_after (gen_label_rtx (), copy_end);
 
-  /* Delete all of the original loop instructions.  Don't delete the 
+  /* Delete all of the original loop instructions.  Don't delete the
      LOOP_BEG note, or the first code label in the loop.  */
 
   insn = NEXT_INSN (copy_start);
@@ -1281,6 +1273,10 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
      not taken.  */
   if (exit_label)
     emit_label_after (exit_label, loop_end);
+
+ egress:
+  if (map && map->const_equiv_varray)
+    VARRAY_FREE (map->const_equiv_varray);
 }
 \f
 /* Return true if the loop can be safely, and profitably, preconditioned
@@ -1408,11 +1404,10 @@ precondition_loop_p (loop_start, loop_info,
       return 0;
     }
 
-  /* ??? Note that if iteration_info is modifed to allow GIV iterators
-     such as "while (i-- > 0)", the initial value will be one too small.
-     In this case, loop_iteration_var could be used to determine
-     the correct initial value, provided the loop has not been reversed.
-     
+  /* Note that iteration_info biases the initial value for GIV iterators
+     such as "while (i-- > 0)" so that we can calculate the number of
+     iterations just like for BIV iterators.
+
      Also note that the absolute values of initial_value and
      final_value are unimportant as only their difference is used for
      calculating the number of loop iterations.  */
@@ -1496,7 +1491,7 @@ calculate_giv_inc (pattern, src_insn, regno)
       pattern = PATTERN (src_insn);
       if (GET_CODE (SET_SRC (pattern)) != PLUS)
        abort ();
-                 
+
       /* The last insn emitted is not needed, so delete it to avoid confusing
         the second cse pass.  This insn sets the giv unnecessarily.  */
       delete_insn (get_last_insn ());
@@ -1520,11 +1515,11 @@ calculate_giv_inc (pattern, src_insn, regno)
       /* Some ports store large constants in memory and add a REG_EQUAL
         note to the store insn.  */
       else if (GET_CODE (increment) == MEM)
-        {
-          rtx note = find_reg_note (src_insn, REG_EQUAL, 0);
-          if (note)
-            increment = XEXP (note, 0);
-        }
+       {
+         rtx note = find_reg_note (src_insn, REG_EQUAL, 0);
+         if (note)
+           increment = XEXP (note, 0);
+       }
 
       else if (GET_CODE (increment) == IOR
               || GET_CODE (increment) == ASHIFT
@@ -1554,7 +1549,7 @@ calculate_giv_inc (pattern, src_insn, regno)
 
       if (GET_CODE (increment) != CONST_INT)
        abort ();
-                 
+
       /* The insn loading the constant into a register is no longer needed,
         so delete it.  */
       delete_insn (get_last_insn ());
@@ -1638,7 +1633,7 @@ final_reg_note_copy (notes, map)
 
 /* Copy each instruction in the loop, substituting from map as appropriate.
    This is very similar to a loop in expand_inline_function.  */
-  
+
 static void
 copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                unroll_type, start_label, loop_end, insert_before,
@@ -1669,35 +1664,41 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
     {
       final_label = gen_label_rtx ();
       set_label_in_map (map, CODE_LABEL_NUMBER (start_label),
-                       final_label); 
+                       final_label);
     }
   else
     set_label_in_map (map, CODE_LABEL_NUMBER (start_label), start_label);
 
   start_sequence ();
-  
+
+  /* Emit a NOTE_INSN_DELETED to force at least two insns onto the sequence.
+     Else gen_sequence could return a raw pattern for a jump which we pass
+     off to emit_insn_before (instead of emit_jump_insn_before) which causes
+     a variety of losing behaviors later.  */
+  emit_note (0, NOTE_INSN_DELETED);
+
   insn = copy_start;
   do
     {
       insn = NEXT_INSN (insn);
-      
+
       map->orig_asm_operands_vector = 0;
-      
+
       switch (GET_CODE (insn))
        {
        case INSN:
          pattern = PATTERN (insn);
          copy = 0;
          giv_inc = 0;
-         
+
          /* Check to see if this is a giv that has been combined with
-            some split address givs.  (Combined in the sense that 
+            some split address givs.  (Combined in the sense that
             `combine_givs' in loop.c has put two givs in the same register.)
             In this case, we must search all givs based on the same biv to
             find the address givs.  Then split the address givs.
             Do this before splitting the giv, since that may map the
             SET_DEST to a new register.  */
-         
+
          if ((set = single_set (insn))
              && GET_CODE (SET_DEST (set)) == REG
              && addr_combined_regs[REGNO (SET_DEST (set))])
@@ -1705,17 +1706,18 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
              struct iv_class *bl;
              struct induction *v, *tv;
              int regno = REGNO (SET_DEST (set));
-             
+
              v = addr_combined_regs[REGNO (SET_DEST (set))];
              bl = reg_biv_class[REGNO (v->src_reg)];
-             
+
              /* Although the giv_inc amount is not needed here, we must call
                 calculate_giv_inc here since it might try to delete the
                 last insn emitted.  If we wait until later to call it,
                 we might accidentally delete insns generated immediately
                 below by emit_unrolled_add.  */
 
-             giv_inc = calculate_giv_inc (set, insn, regno);
+             if (! derived_regs[regno])
+               giv_inc = calculate_giv_inc (set, insn, regno);
 
              /* Now find all address giv's that were combined with this
                 giv 'v'.  */
@@ -1734,24 +1736,24 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                    if (tv->mult_val != v->mult_val)
                      this_giv_inc = (this_giv_inc / INTVAL (v->mult_val)
                                      * INTVAL (tv->mult_val));
-                      
+
                    tv->dest_reg = plus_constant (tv->dest_reg, this_giv_inc);
                    *tv->location = tv->dest_reg;
-                   
+
                    if (last_iteration && unroll_type != UNROLL_COMPLETELY)
                      {
                        /* Must emit an insn to increment the split address
                           giv.  Add in the const_adjust field in case there
                           was a constant eliminated from the address.  */
                        rtx value, dest_reg;
-                       
+
                        /* tv->dest_reg will be either a bare register,
                           or else a register plus a constant.  */
                        if (GET_CODE (tv->dest_reg) == REG)
                          dest_reg = tv->dest_reg;
                        else
                          dest_reg = XEXP (tv->dest_reg, 0);
-                       
+
                        /* Check for shared address givs, and avoid
                           incrementing the shared pseudo reg more than
                           once.  */
@@ -1770,7 +1772,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                            emit_unrolled_add (dest_reg, XEXP (value, 0),
                                               XEXP (value, 1));
                          }
-                       
+
                        /* Reset the giv to be just the register again, in case
                           it is used after the set we have just emitted.
                           We must subtract the const_adjust factor added in
@@ -1781,39 +1783,53 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                      }
                  }
            }
-         
+
          /* If this is a setting of a splittable variable, then determine
             how to split the variable, create a new set based on this split,
             and set up the reg_map so that later uses of the variable will
             use the new split variable.  */
-         
+
          dest_reg_was_split = 0;
-         
+
          if ((set = single_set (insn))
              && GET_CODE (SET_DEST (set)) == REG
              && splittable_regs[REGNO (SET_DEST (set))])
            {
              int regno = REGNO (SET_DEST (set));
-             
+             int src_regno;
+
              dest_reg_was_split = 1;
-             
-             /* Compute the increment value for the giv, if it wasn't
-                already computed above.  */
 
-             if (giv_inc == 0)
-               giv_inc = calculate_giv_inc (set, insn, regno);
              giv_dest_reg = SET_DEST (set);
-             giv_src_reg = SET_DEST (set);
+             if (derived_regs[regno])
+               {
+                 /* ??? This relies on SET_SRC (SET) to be of
+                    the form (plus (reg) (const_int)), and thus
+                    forces recombine_givs to restrict the kind
+                    of giv derivations it does before unrolling.  */
+                 giv_src_reg = XEXP (SET_SRC (set), 0);
+                 giv_inc = XEXP (SET_SRC (set), 1);
+               }
+             else
+               {
+                 giv_src_reg = giv_dest_reg;
+                 /* Compute the increment value for the giv, if it wasn't
+                    already computed above.  */
+                 if (giv_inc == 0)
+                   giv_inc = calculate_giv_inc (set, insn, regno);
+               }
+             src_regno = REGNO (giv_src_reg);
 
              if (unroll_type == UNROLL_COMPLETELY)
                {
                  /* Completely unrolling the loop.  Set the induction
                     variable to a known constant value.  */
-                 
+
                  /* The value in splittable_regs may be an invariant
                     value, so we must use plus_constant here.  */
                  splittable_regs[regno]
-                   = plus_constant (splittable_regs[regno], INTVAL (giv_inc));
+                   = plus_constant (splittable_regs[src_regno],
+                                    INTVAL (giv_inc));
 
                  if (GET_CODE (splittable_regs[regno]) == PLUS)
                    {
@@ -1836,7 +1852,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                     be a constant plus the original register.  Except
                     on the last iteration, when the result has to
                     go back into the original iteration var register.  */
-                 
+
                  /* Handle bivs which must be mapped to a new register
                     when split.  This happens for bivs which need their
                     final value set before loop entry.  The new register
@@ -1844,23 +1860,23 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                     induction entry by find_splittable_regs.  */
 
                  if (regno < max_reg_before_loop
-                     && reg_iv_type[regno] == BASIC_INDUCT)
+                     && REG_IV_TYPE (regno) == BASIC_INDUCT)
                    {
                      giv_src_reg = reg_biv_class[regno]->biv->src_reg;
                      giv_dest_reg = giv_src_reg;
                    }
-                 
+
 #if 0
                  /* If non-reduced/final-value givs were split, then
                     this would have to remap those givs also.  See
                     find_splittable_regs.  */
 #endif
-                 
+
                  splittable_regs[regno]
                    = GEN_INT (INTVAL (giv_inc)
-                              + INTVAL (splittable_regs[regno]));
+                              + INTVAL (splittable_regs[src_regno]));
                  giv_inc = splittable_regs[regno];
-                 
+
                  /* Now split the induction variable by changing the dest
                     of this insn to a new register, and setting its
                     reg_map entry to point to this new register.
@@ -1904,7 +1920,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
              copy = emit_insn (pattern);
            }
          REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map);
-         
+
 #ifdef HAVE_cc0
          /* If this insn is setting CC0, it may need to look at
             the insn that uses CC0 to see what type of insn it is.
@@ -1939,12 +1955,13 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
            {
              int regno = REGNO (SET_DEST (pattern));
 
-             if (regno < map->const_equiv_map_size
-                 && map->const_age_map[regno] == map->const_age)
-               map->const_age_map[regno] = -1;
+             if (regno < VARRAY_SIZE (map->const_equiv_varray)
+                 && (VARRAY_CONST_EQUIV (map->const_equiv_varray, regno).age
+                     == map->const_age))
+               VARRAY_CONST_EQUIV (map->const_equiv_varray, regno).age = -1;
            }
          break;
-         
+
        case JUMP_INSN:
          pattern = copy_rtx_and_substitute (PATTERN (insn), map);
          copy = emit_jump_insn (pattern);
@@ -1988,7 +2005,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                    abort ();
                }
            }
-         
+
 #ifdef HAVE_cc0
          if (cc0_insn)
            try_constants (cc0_insn, map);
@@ -2026,10 +2043,10 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                     for a switch statement.  This label must have been mapped,
                     so just use the label_map to get the new jump label.  */
                  JUMP_LABEL (copy)
-                   = get_label_from_map (map, 
-                                         CODE_LABEL_NUMBER (JUMP_LABEL (insn))); 
+                   = get_label_from_map (map,
+                                         CODE_LABEL_NUMBER (JUMP_LABEL (insn)));
                }
-         
+
              /* If this is a non-local jump, then must increase the label
                 use count so that the label will not be deleted when the
                 original jump is deleted.  */
@@ -2076,7 +2093,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                emit_barrier ();
            }
          break;
-         
+
        case CALL_INSN:
          pattern = copy_rtx_and_substitute (PATTERN (insn), map);
          copy = emit_call_insn (pattern);
@@ -2096,9 +2113,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
 
          /* Be lazy and assume CALL_INSNs clobber all hard registers.  */
          for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-           map->const_equiv_map[i] = 0;
+           VARRAY_CONST_EQUIV (map->const_equiv_varray, i).rtx = 0;
          break;
-         
+
        case CODE_LABEL:
          /* If this is the loop start label, then we don't need to emit a
             copy of this label since no one will use it.  */
@@ -2110,33 +2127,38 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
              map->const_age++;
            }
          break;
-         
+
        case BARRIER:
          copy = emit_barrier ();
          break;
-         
+
        case NOTE:
-         /* VTOP notes are valid only before the loop exit test.  If placed
-            anywhere else, loop may generate bad code.  */
-            
+         /* VTOP and CONT notes are valid only before the loop exit test.
+            If placed anywhere else, loop may generate bad code.  */
+         /* BASIC_BLOCK notes exist to stabilize basic block structures with
+            the associated rtl.  We do not want to share the structure in 
+            this new block.  */
+
          if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
-             && (NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP
+             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
+             && ((NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP
+                  && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_CONT)
                  || (last_iteration && unroll_type != UNROLL_COMPLETELY)))
            copy = emit_note (NOTE_SOURCE_FILE (insn),
                              NOTE_LINE_NUMBER (insn));
          else
            copy = 0;
          break;
-         
+
        default:
          abort ();
          break;
        }
-      
+
       map->insn_map[INSN_UID (insn)] = copy;
     }
   while (insn != copy_end);
-  
+
   /* Now finish coping the REG_NOTES.  */
   insn = copy_start;
   do
@@ -2164,7 +2186,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
       for (insn = copy_notes_from; insn != loop_end; insn = NEXT_INSN (insn))
        {
          if (GET_CODE (insn) == NOTE
-             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
+             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
+             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)
            emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
        }
     }
@@ -2231,7 +2254,7 @@ back_branch_in_range_p (insn, loop_start, loop_end)
       if (GET_CODE (p) == JUMP_INSN)
        {
          target_insn = JUMP_LABEL (p);
-         
+
          /* Search from loop_start to insn, to see if one of them is
             the target_insn.  We can't use INSN_LUID comparisons here,
             since insn may not have an LUID entry.  */
@@ -2297,7 +2320,7 @@ fold_rtx_mult_add (mult1, mult2, add1, mode)
    Returns the increment value as an rtx, simplified as much as possible,
    if it can be calculated.  Otherwise, returns 0.  */
 
-rtx 
+rtx
 biv_total_increment (bl, loop_start, loop_end)
      struct iv_class *bl;
      rtx loop_start, loop_end;
@@ -2352,7 +2375,7 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
 
   /* If this is a new register, can't handle it since we don't have any
      reg_iv_type entry for it.  */
-  if (REGNO (iteration_var) >= max_reg_before_loop)
+  if ((unsigned) REGNO (iteration_var) >= reg_iv_type->num_elements)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -2378,44 +2401,62 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
                 "Loop unrolling: Iteration var not an integer.\n");
       return;
     }
-  else if (reg_iv_type[REGNO (iteration_var)] == BASIC_INDUCT)
+  else if (REG_IV_TYPE (REGNO (iteration_var)) == BASIC_INDUCT)
     {
+      /* When reg_iv_type / reg_iv_info is resized for biv increments
+        that are turned into givs, reg_biv_class is not resized.
+        So check here that we don't make an out-of-bounds access.  */
+      if (REGNO (iteration_var) >= max_reg_before_loop)
+       abort ();
+
       /* Grab initial value, only useful if it is a constant.  */
       bl = reg_biv_class[REGNO (iteration_var)];
       *initial_value = bl->initial_value;
 
       *increment = biv_total_increment (bl, loop_start, loop_end);
     }
-  else if (reg_iv_type[REGNO (iteration_var)] == GENERAL_INDUCT)
-    {
-#if 1
-      /* ??? The code below does not work because the incorrect number of
-        iterations is calculated when the biv is incremented after the giv
-        is set (which is the usual case).  This can probably be accounted
-        for by biasing the initial_value by subtracting the amount of the
-        increment that occurs between the giv set and the giv test.  However,
-        a giv as an iterator is very rare, so it does not seem worthwhile
-        to handle this.  */
-      /* ??? An example failure is: i = 6; do {;} while (i++ < 9).  */
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
-                "Loop unrolling: Giv iterators are not handled.\n");
-      return;
-#else
-      /* Initial value is mult_val times the biv's initial value plus
-        add_val.  Only useful if it is a constant.  */
-      v = reg_iv_info[REGNO (iteration_var)];
+  else if (REG_IV_TYPE (REGNO (iteration_var)) == GENERAL_INDUCT)
+    {
+      HOST_WIDE_INT offset = 0;
+      struct induction *v = REG_IV_INFO (REGNO (iteration_var));
+
+      if (REGNO (v->src_reg) >= max_reg_before_loop)
+       abort ();
+
       bl = reg_biv_class[REGNO (v->src_reg)];
-      *initial_value = fold_rtx_mult_add (v->mult_val, bl->initial_value,
-                                         v->add_val, v->mode);
-      
+
       /* Increment value is mult_val times the increment value of the biv.  */
 
       *increment = biv_total_increment (bl, loop_start, loop_end);
       if (*increment)
-       *increment = fold_rtx_mult_add (v->mult_val, *increment, const0_rtx,
-                                       v->mode);
-#endif
+       {
+         struct induction *biv_inc;
+
+         *increment
+           = fold_rtx_mult_add (v->mult_val, *increment, const0_rtx, v->mode);
+         /* The caller assumes that one full increment has occured at the
+            first loop test.  But that's not true when the biv is incremented
+            after the giv is set (which is the usual case), e.g.:
+            i = 6; do {;} while (i++ < 9) .
+            Therefore, we bias the initial value by subtracting the amount of
+            the increment that occurs between the giv set and the giv test.  */
+         for (biv_inc = bl->biv; biv_inc; biv_inc = biv_inc->next_iv)
+           {
+             if (loop_insn_first_p (v->insn, biv_inc->insn))
+               offset -= INTVAL (biv_inc->add_val);
+           }
+         offset *= INTVAL (v->mult_val);
+       }
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Loop unrolling: Giv iterator, initial value bias %ld.\n",
+                (long) offset);
+      /* Initial value is mult_val times the biv's initial value plus
+        add_val.  Only useful if it is a constant.  */
+      *initial_value
+       = fold_rtx_mult_add (v->mult_val,
+                            plus_constant (bl->initial_value, offset),
+                            v->add_val, v->mode);
     }
   else
     {
@@ -2686,7 +2727,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
          && (! v->always_computable
              || back_branch_in_range_p (v->insn, loop_start, loop_end)))
        continue;
-      
+
       /* The giv increment value must be a constant.  */
       giv_inc = fold_rtx_mult_add (v->mult_val, increment, const0_rtx,
                                   v->mode);
@@ -2698,7 +2739,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
         the loop, or else the final value of the giv must be known.
         Otherwise, it is not safe to split the giv since it may not have the
         proper value on loop exit.  */
-         
+
       /* The used outside loop test will fail for DEST_ADDR givs.  They are
         never used outside the loop anyways, so it is always safe to split a
         DEST_ADDR giv.  */
@@ -2722,6 +2763,10 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
              /* Line above always fails if INSN was moved by loop opt.  */
              || (uid_luid[REGNO_LAST_UID (REGNO (v->dest_reg))]
                  >= INSN_LUID (loop_end)))
+         /* Givs made from biv increments are missed by the above test, so
+            test explicitly for them.  */
+         && (REGNO (v->dest_reg) < first_increment_giv
+             || REGNO (v->dest_reg) > last_increment_giv)
          && ! (final_value = v->final_value))
        continue;
 
@@ -2742,11 +2787,11 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
          emit_insn_before (gen_move_insn (tem, v->dest_reg), loop_start);
          emit_insn_before (gen_move_insn (v->dest_reg, final_value),
                            loop_start);
-         
+
          if (loop_dump_stream)
            fprintf (loop_dump_stream, "Giv %d mapped to %d for split.\n",
                     REGNO (v->dest_reg), REGNO (tem));
-         
+
          v->src_reg = tem;
        }
 #endif
@@ -2820,8 +2865,9 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                                    v->add_val, tem, loop_start);
                  value = tem;
                }
-               
+
              splittable_regs[REGNO (v->new_reg)] = value;
+             derived_regs[REGNO (v->new_reg)] = v->derived_from != 0;
            }
          else
            {
@@ -2861,8 +2907,11 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                          To share a register here, the values must be
                          equal.  */
                       && rtx_equal_p (v->same->mult_val, v->mult_val)
-                      && rtx_equal_p (v->same->add_val, v->add_val))
-
+                      && rtx_equal_p (v->same->add_val, v->add_val)
+                      /* If the memory references have different modes,
+                         then the address may not be valid and we must
+                         not share registers.  */
+                      && verify_addresses (v, giv_inc, unroll_number))
                {
                  v->dest_reg = v->same->dest_reg;
                  v->shared = 1;
@@ -2874,17 +2923,38 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                     Emit insn to initialize its value before loop start.  */
 
                  rtx tem = gen_reg_rtx (v->mode);
+                 struct induction *same = v->same;
+                 rtx new_reg = v->new_reg;
                  record_base_value (REGNO (tem), v->add_val, 0);
 
+                 if (same && same->derived_from)
+                   {
+                     /* calculate_giv_inc doesn't work for derived givs.
+                        copy_loop_body works around the problem for the
+                        DEST_REG givs themselves, but it can't handle
+                        DEST_ADDR givs that have been combined with
+                        a derived DEST_REG giv.
+                        So Handle V as if the giv from which V->SAME has
+                        been derived has been combined with V.
+                        recombine_givs only derives givs from givs that
+                        are reduced the ordinary, so we need not worry
+                        about same->derived_from being in turn derived.  */
+
+                     same = same->derived_from;
+                     new_reg = express_from (same, v);
+                     new_reg = replace_rtx (new_reg, same->dest_reg,
+                                            same->new_reg);
+                   }
+
                  /* If the address giv has a constant in its new_reg value,
                     then this constant can be pulled out and put in value,
                     instead of being part of the initialization code.  */
-                 
-                 if (GET_CODE (v->new_reg) == PLUS
-                     && GET_CODE (XEXP (v->new_reg, 1)) == CONST_INT)
+
+                 if (GET_CODE (new_reg) == PLUS
+                     && GET_CODE (XEXP (new_reg, 1)) == CONST_INT)
                    {
                      v->dest_reg
-                       = plus_constant (tem, INTVAL (XEXP (v->new_reg,1)));
+                       = plus_constant (tem, INTVAL (XEXP (new_reg, 1)));
 
                      /* Only succeed if this will give valid addresses.
                         Try to validate both the first and the last
@@ -2895,9 +2965,9 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                          /* Save the negative of the eliminated const, so
                             that we can calculate the dest_reg's increment
                             value later.  */
-                         v->const_adjust = - INTVAL (XEXP (v->new_reg, 1));
+                         v->const_adjust = - INTVAL (XEXP (new_reg, 1));
 
-                         v->new_reg = XEXP (v->new_reg, 0);
+                         new_reg = XEXP (new_reg, 0);
                          if (loop_dump_stream)
                            fprintf (loop_dump_stream,
                                     "Eliminating constant from giv %d\n",
@@ -2908,7 +2978,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                    }
                  else
                    v->dest_reg = tem;
-                 
+
                  /* If the address hasn't been checked for validity yet, do so
                     now, and fail completely if either the first or the last
                     unrolled copy of the address is not a valid address
@@ -2926,7 +2996,10 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                                 INSN_UID (v->insn));
                      continue;
                    }
-                 
+
+                 v->new_reg = new_reg;
+                 v->same = same;
+
                  /* We set this after the address check, to guarantee that
                     the register will be initialized.  */
                  v->unrolled = 1;
@@ -2965,7 +3038,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
              else
                {
                  v->dest_reg = value;
-                 
+
                  /* Check the resulting address for validity, and fail
                     if the resulting address would be invalid.  */
                  if (! verify_addresses (v, giv_inc, unroll_number))
@@ -2980,29 +3053,41 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                                 INSN_UID (v->insn));
                      continue;
                    }
+                 if (v->same && v->same->derived_from)
+                   {
+                     /* Handle V as if the giv from which V->SAME has
+                        been derived has been combined with V.  */
+
+                     v->same = v->same->derived_from;
+                     v->new_reg = express_from (v->same, v);
+                     v->new_reg = replace_rtx (v->new_reg, v->same->dest_reg,
+                                               v->same->new_reg);
+                   }
+
                }
-             
+
              /* Store the value of dest_reg into the insn.  This sharing
                 will not be a problem as this insn will always be copied
                 later.  */
-             
+
              *v->location = v->dest_reg;
-             
+
              /* If this address giv is combined with a dest reg giv, then
                 save the base giv's induction pointer so that we will be
                 able to handle this address giv properly.  The base giv
                 itself does not have to be splittable.  */
-             
+
              if (v->same && v->same->giv_type == DEST_REG)
                addr_combined_regs[REGNO (v->same->new_reg)] = v->same;
-             
+
              if (GET_CODE (v->new_reg) == REG)
                {
                  /* This giv maybe hasn't been combined with any others.
                     Make sure that it's giv is marked as splittable here.  */
-                 
+
                  splittable_regs[REGNO (v->new_reg)] = value;
-                 
+                 derived_regs[REGNO (v->new_reg)] = v->derived_from != 0;
+
                  /* Make it appear to depend upon itself, so that the
                     giv will be properly split in the main loop above.  */
                  if (! v->same)
@@ -3025,7 +3110,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
             it makes sense to reduce&split givs when possible, as this will
             result in simpler instructions, and will not require that a reg
             be live across loop iterations.  */
-         
+
          splittable_regs[REGNO (v->dest_reg)] = value;
          fprintf (stderr, "Giv %d at insn %d not reduced\n",
                   REGNO (v->dest_reg), INSN_UID (v->insn));
@@ -3033,7 +3118,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
          continue;
 #endif
        }
-      
+
       /* Unreduced givs are only updated once by definition.  Reduced givs
         are updated as many times as their biv is.  Mark it so if this is
         a splittable register.  Don't need to do anything for address givs
@@ -3045,15 +3130,20 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
          if (! v->ignore)
            count = reg_biv_class[REGNO (v->src_reg)]->biv_count;
 
+         if (count > 1 && v->derived_from)
+            /* In this case, there is one set where the giv insn was and one
+               set each after each biv increment.  (Most are likely dead.)  */
+           count++;
+
          splittable_regs_updates[REGNO (v->new_reg)] = count;
        }
 
       result++;
-      
+
       if (loop_dump_stream)
        {
          int regnum;
-         
+
          if (GET_CODE (v->dest_reg) == CONST_INT)
            regnum = -1;
          else if (GET_CODE (v->dest_reg) != REG)
@@ -3090,7 +3180,7 @@ reg_dead_after_loop (reg, loop_start, loop_end)
      all exits of inner nested loops that would exit this loop.  We don't
      have any way to identify those, so we just give up if there are any
      such inner loop exits.  */
-     
+
   for (label = loop_number_exit_labels[this_loop_num]; label;
        label = LABEL_NEXTREF (label))
     label_count++;
@@ -3148,7 +3238,7 @@ reg_dead_after_loop (reg, loop_start, loop_end)
 
 /* Try to calculate the final value of the biv, the value it will have at
    the end of the loop.  If we can do it, return that value.  */
-  
+
 rtx
 final_biv_value (bl, loop_start, loop_end, n_iterations)
      struct iv_class *bl;
@@ -3171,7 +3261,7 @@ final_biv_value (bl, loop_start, loop_end, n_iterations)
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
                 "Final biv value for %d, reversed biv.\n", bl->regno);
-                
+
       return const0_rtx;
     }
 
@@ -3186,7 +3276,7 @@ final_biv_value (bl, loop_start, loop_end, n_iterations)
       && invariant_p (bl->initial_value))
     {
       increment = biv_total_increment (bl, loop_start, loop_end);
-      
+
       if (increment && invariant_p (increment))
        {
          /* Can calculate the loop exit value, emit insns after loop
@@ -3204,7 +3294,7 @@ final_biv_value (bl, loop_start, loop_end, n_iterations)
          if (loop_dump_stream)
            fprintf (loop_dump_stream,
                     "Final biv value for %d, calculated.\n", bl->regno);
-         
+
          return tem;
        }
     }
@@ -3255,7 +3345,7 @@ final_giv_value (v, loop_start, loop_end, n_iterations)
   /* Try to calculate the final value as a function of the biv it depends
      upon.  The only exit from the loop must be the fall through at the bottom
      (otherwise it may not have its final value when the loop exits).  */
-      
+
   /* ??? Can calculate the final giv value by subtracting off the
      extra biv increments times the giv's mult_val.  The loop must have
      only one exit for this to work, but the loop iterations does not need
@@ -3282,7 +3372,7 @@ final_giv_value (v, loop_start, loop_end, n_iterations)
        {
          /* Can calculate the loop exit value of its biv as
             (n_iterations * increment) + initial_value */
-             
+
          /* The loop exit value of the giv is then
             (final_biv_value - extra increments) * mult_val + add_val.
             The extra increments are any increments to the biv which
@@ -3316,11 +3406,11 @@ final_giv_value (v, loop_start, loop_end, n_iterations)
                    emit_insn_before (seq, insert_before);
                  }
            }
-         
+
          /* Now calculate the giv's final value.  */
          emit_iv_add_mult (tem, v->mult_val, v->add_val, tem,
                            insert_before);
-         
+
          if (loop_dump_stream)
            fprintf (loop_dump_stream,
                     "Final giv value for %d, calc from biv's value.\n",
@@ -3360,13 +3450,13 @@ loop_find_equiv_value (loop_start, reg)
 {
   rtx insn, set;
   rtx ret;
-  
+
   ret = reg;
   for (insn = PREV_INSN (loop_start); insn ; insn = PREV_INSN (insn))
     {
       if (GET_CODE (insn) == CODE_LABEL)
        break;
-      
+
       else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
               && reg_set_p (reg, insn))
        {
@@ -3377,7 +3467,7 @@ loop_find_equiv_value (loop_start, reg)
                  && (SET_DEST (set) == reg))
            {
              rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-             
+
              /* Only use the REG_EQUAL note if it is a constant.
                 Other things, divide in particular, will cause
                 problems later if we use them.  */
@@ -3394,6 +3484,72 @@ loop_find_equiv_value (loop_start, reg)
 }
 
 
+/* Return a simplified rtx for the expression OP - REG.
+
+   REG must appear in OP, and OP must be a register or the sum of a register
+   and a second term.
+
+   Thus, the return value must be const0_rtx or the second term.
+
+   The caller is responsible for verifying that REG appears in OP and OP has
+   the proper form.  */
+
+static rtx
+subtract_reg_term (op, reg)
+     rtx op, reg;
+{
+  if (op == reg)
+    return const0_rtx;
+  if (GET_CODE (op) == PLUS)
+    {
+      if (XEXP (op, 0) == reg)
+       return XEXP (op, 1);
+      else if (XEXP (op, 1) == reg)
+       return XEXP (op, 0);
+    }
+  /* OP does not contain REG as a term.  */
+  abort ();
+}
+
+
+/* Find and return register term common to both expressions OP0 and
+   OP1 or NULL_RTX if no such term exists.  Each expression must be a
+   REG or a PLUS of a REG.  */
+
+static rtx
+find_common_reg_term (op0, op1)
+     rtx op0, op1;
+{
+  if ((GET_CODE (op0) == REG || GET_CODE (op0) == PLUS)
+      && (GET_CODE (op1) == REG || GET_CODE (op1) == PLUS))
+    {
+      rtx op00;
+      rtx op01;
+      rtx op10;
+      rtx op11;
+
+      if (GET_CODE (op0) == PLUS)
+       op01 = XEXP (op0, 1), op00 = XEXP (op0, 0);
+      else
+       op01 = const0_rtx, op00 = op0;
+
+      if (GET_CODE (op1) == PLUS)
+       op11 = XEXP (op1, 1), op10 = XEXP (op1, 0);
+      else
+       op11 = const0_rtx, op10 = op1;
+
+      /* Find and return common register term if present.  */
+      if (REG_P (op00) && (op00 == op10 || op00 == op11))
+       return op00;
+      else if (REG_P (op01) && (op01 == op10 || op01 == op11))
+       return op01;
+    }
+
+  /* No common register term found.  */
+  return NULL_RTX;
+}
+
+
 /* Calculate the number of loop iterations.  Returns the exact number of loop
    iterations if it can be calculated, otherwise returns zero.  */
 
@@ -3411,6 +3567,8 @@ loop_iterations (loop_start, loop_end, loop_info)
   int increment_dir;
   int unsigned_p, compare_dir, final_larger;
   rtx last_loop_insn;
+  rtx vtop;
+  rtx reg_term;
 
   loop_info->n_iterations = 0;
   loop_info->initial_value = 0;
@@ -3421,23 +3579,45 @@ loop_iterations (loop_start, loop_end, loop_info)
   loop_info->increment = 0;
   loop_info->iteration_var = 0;
   loop_info->unroll_number = 1;
+  loop_info->vtop = 0;
 
-  /* First find the iteration variable.  If the last insn is a conditional
-     branch, and the insn before tests a register value, make that the
-     iteration variable.  */
-  
   /* We used to use prev_nonnote_insn here, but that fails because it might
      accidentally get the branch for a contained loop if the branch for this
      loop was deleted.  We can only trust branches immediately before the
      loop_end.  */
   last_loop_insn = PREV_INSN (loop_end);
 
+  /* ??? We should probably try harder to find the jump insn
+     at the end of the loop.  The following code assumes that
+     the last loop insn is a jump to the top of the loop.  */
+  if (GET_CODE (last_loop_insn) != JUMP_INSN)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Loop iterations: No final conditional branch found.\n");
+      return 0;
+    }
+
+  /* If there is a more than a single jump to the top of the loop
+     we cannot (easily) determine the iteration count.  */
+  if (LABEL_NUSES (JUMP_LABEL (last_loop_insn)) > 1)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Loop iterations: Loop has multiple back edges.\n");
+      return 0;
+    }
+
+  /* Find the iteration variable.  If the last insn is a conditional
+     branch, and the insn before tests a register value, make that the
+     iteration variable.  */
+
   comparison = get_condition_for_loop (last_loop_insn);
   if (comparison == 0)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
-                "Loop iterations: No final conditional branch found.\n");
+                "Loop iterations: No final comparison found.\n");
       return 0;
     }
 
@@ -3448,6 +3628,25 @@ loop_iterations (loop_start, loop_end, loop_info)
   iteration_var = XEXP (comparison, 0);
   comparison_value = XEXP (comparison, 1);
 
+  /* Check if there is a NOTE_INSN_LOOP_VTOP note.  If there is,
+     that means that this is a for or while style loop, with
+     a loop exit test at the start.  Thus, we can assume that
+     the loop condition was true when the loop was entered.
+
+     We start at the end and search backwards for the previous
+     NOTE.  If there is no NOTE_INSN_LOOP_VTOP for this loop,
+     the search will stop at the NOTE_INSN_LOOP_CONT.  */
+  vtop = loop_end;
+  do
+    vtop = PREV_INSN (vtop);
+  while (GET_CODE (vtop) != NOTE
+        || NOTE_LINE_NUMBER (vtop) > 0
+        || NOTE_LINE_NUMBER (vtop) == NOTE_REPEATED_LINE_NUMBER
+        || NOTE_LINE_NUMBER (vtop) == NOTE_INSN_DELETED);
+  if (NOTE_LINE_NUMBER (vtop) != NOTE_INSN_LOOP_VTOP)
+    vtop = NULL_RTX;
+  loop_info->vtop = vtop;
+
   if (GET_CODE (iteration_var) != REG)
     {
       if (loop_dump_stream)
@@ -3456,10 +3655,10 @@ loop_iterations (loop_start, loop_end, loop_info)
       return 0;
     }
 
-  /* Loop iterations is always called before any new registers are created
-     now, so this should never occur.  */
+  /* The only new registers that care created before loop iterations are
+     givs made from biv increments, so this should never occur.  */
 
-  if (REGNO (iteration_var) >= max_reg_before_loop)
+  if ((unsigned) REGNO (iteration_var) >= reg_iv_type->num_elements)
     abort ();
 
   iteration_info (iteration_var, &initial_value, &increment,
@@ -3532,7 +3731,7 @@ loop_iterations (loop_start, loop_end, loop_info)
   /* Save the calculated values describing this loop's bounds, in case
      precondition_loop_p will need them later.  These values can not be
      recalculated inside precondition_loop_p because strength reduction
-     optimizations may obscure the loop's structure.  
+     optimizations may obscure the loop's structure.
 
      These values are only required by precondition_loop_p and insert_bct
      whenever the number of iterations cannot be computed at compile time.
@@ -3545,66 +3744,94 @@ loop_iterations (loop_start, loop_end, loop_info)
   loop_info->iteration_var = iteration_var;
   loop_info->comparison_code = comparison_code;
 
-  if (REG_P (initial_value))
-    {
-      rtx temp = final_value;
-
-      /* initial_value = reg1, final_value = reg2 + const, where reg1
-        != reg2.  Try to find what reg1 is equivalent to.  Hopefully
-        it will either be reg2 or reg2 plus a constant.  */
-      if (GET_CODE (temp) == PLUS)
-       temp = XEXP (temp, 0);
-      if (REG_P (temp) && REGNO (temp) != REGNO (initial_value))
-       initial_value = loop_find_equiv_value (loop_start, initial_value);
-    }
+  /* Try to determine the iteration count for loops such
+     as (for i = init; i < init + const; i++).  When running the
+     loop optimization twice, the first pass often converts simple
+     loops into this form.  */
 
-  /* If have initial_value = reg + const1 and final_value = reg +
-     const2, then replace initial_value with const1 and final_value
-     with const2.  This should be safe since we are protected by the
-     initial comparison before entering the loop.  */
-  if ((GET_CODE (initial_value) == REG || GET_CODE (initial_value) == PLUS)
-      && (GET_CODE (final_value) == REG || GET_CODE (final_value) == PLUS))
+  if (REG_P (initial_value))
     {
-      rtx init_op0;
-      rtx fini_op0;
-      rtx init_op1;
-      rtx fini_op1;
-
-      if (GET_CODE (initial_value) == PLUS)
-       init_op1 = XEXP (initial_value, 1), init_op0 = XEXP (initial_value, 0);
-      else
-       init_op1 = const0_rtx, init_op0 = initial_value;
+      rtx reg1;
+      rtx reg2;
+      rtx const2;
 
+      reg1 = initial_value;
       if (GET_CODE (final_value) == PLUS)
-       fini_op1 = XEXP (final_value, 1), fini_op0 = XEXP (final_value, 0);
+       reg2 = XEXP (final_value, 0), const2 = XEXP (final_value, 1);
       else
-       fini_op1 = const0_rtx, fini_op0 = final_value;
+       reg2 = final_value, const2 = const0_rtx;
 
-      /* Remove register common factor if present.  */
-      if (REG_P (init_op0) && init_op0 == fini_op0)
-       {
-         initial_value = init_op1;
-         final_value = fini_op1;
-       }
-      else if (REG_P (init_op0) && init_op0 == fini_op1)
-       {
-         initial_value = init_op1;
-         final_value = fini_op0;
-       }
-      else if (REG_P (init_op1) && init_op1 == fini_op0)
+      /* Check for initial_value = reg1, final_value = reg2 + const2,
+        where reg1 != reg2.  */
+      if (REG_P (reg2) && reg2 != reg1)
        {
-         initial_value = init_op0;
-         final_value = fini_op1;
+         rtx temp;
+
+         /* Find what reg1 is equivalent to.  Hopefully it will
+            either be reg2 or reg2 plus a constant.  */
+         temp = loop_find_equiv_value (loop_start, reg1);
+         if (find_common_reg_term (temp, reg2))
+           initial_value = temp;
+         else
+           {
+             /* Find what reg2 is equivalent to.  Hopefully it will
+                either be reg1 or reg1 plus a constant.  Let's ignore
+                the latter case for now since it is not so common.  */
+             temp = loop_find_equiv_value (loop_start, reg2);
+             if (temp == loop_info->iteration_var)
+               temp = initial_value;
+             if (temp == reg1)
+               final_value = (const2 == const0_rtx)
+                 ? reg1 : gen_rtx_PLUS (GET_MODE (reg1), reg1, const2);
+           }
        }
-      else if (REG_P (init_op1) && init_op1 == fini_op1)
+      else if (loop_info->vtop && GET_CODE (reg2) == CONST_INT)
        {
-         initial_value = init_op0;
-         final_value = fini_op0;
+         rtx temp;
+
+         /*  When running the loop optimizer twice, check_dbra_loop
+             further obfuscates reversible loops of the form:
+             for (i = init; i < init + const; i++).  We often end up with
+             final_value = 0, initial_value = temp, temp = temp2 - init,
+             where temp2 = init + const.  If the loop has a vtop we
+             can replace initial_value with const.  */
+
+         temp = loop_find_equiv_value (loop_start, reg1);
+         if (GET_CODE (temp) == MINUS && REG_P (XEXP (temp, 0)))
+           {
+             rtx temp2 = loop_find_equiv_value (loop_start, XEXP (temp, 0));
+             if (GET_CODE (temp2) == PLUS
+                 && XEXP (temp2, 0) == XEXP (temp, 1))
+               initial_value = XEXP (temp2, 1);
+           }
        }
     }
+
+  /* If have initial_value = reg + const1 and final_value = reg +
+     const2, then replace initial_value with const1 and final_value
+     with const2.  This should be safe since we are protected by the
+     initial comparison before entering the loop if we have a vtop.
+     For example, a + b < a + c is not equivalent to b < c for all a
+     when using modulo arithmetic.
+
+     ??? Without a vtop we could still perform the optimization if we check
+     the initial and final values carefully.  */
+  if (loop_info->vtop
+      && (reg_term = find_common_reg_term (initial_value, final_value)))
+    {
+      initial_value = subtract_reg_term (initial_value, reg_term);
+      final_value = subtract_reg_term (final_value, reg_term);
+    }
+
   loop_info->initial_equiv_value = initial_value;
   loop_info->final_equiv_value = final_value;
-  
+
+  /* For EQ comparison loops, we don't have a valid final value.
+     Check this now so that we won't leave an invalid value if we
+     return early for any other reason.  */
+  if (comparison_code == EQ)
+      loop_info->final_equiv_value = loop_info->final_value = 0;
+
   if (increment == 0)
     {
       if (loop_dump_stream)
@@ -3615,7 +3842,11 @@ loop_iterations (loop_start, loop_end, loop_info)
 
   if (GET_CODE (increment) != CONST_INT)
     {
-      increment = loop_find_equiv_value (loop_start, increment);
+      /* If we have a REG, check to see if REG holds a constant value.  */
+      /* ??? Other RTL, such as (neg (reg)) is possible here, but it isn't
+        clear if it is worthwhile to try to handle such RTL.  */
+      if (GET_CODE (increment) == REG || GET_CODE (increment) == SUBREG)
+       increment = loop_find_equiv_value (loop_start, increment);
 
       if (GET_CODE (increment) != CONST_INT)
        {
@@ -3685,7 +3916,7 @@ loop_iterations (loop_start, loop_end, loop_info)
      will overflow before the loop exits), 4 infinite loop cases, and 15
      immediate exit (0 or 1 iteration depending on loop type) cases.
      Only try to optimize the normal cases.  */
-     
+
   /* (compare_dir/final_larger/increment_dir)
      Normal cases: (0/-1/-1), (0/1/1), (-1/-1/-1), (1/1/1)
      Reverse cases: (0/-1/1), (0/1/-1), (-1/-1/1), (1/1/-1)
@@ -3782,10 +4013,10 @@ remap_split_bivs (x)
         have to remap those givs also.  */
 #endif
       if (REGNO (x) < max_reg_before_loop
-         && reg_iv_type[REGNO (x)] == BASIC_INDUCT)
+         && REG_IV_TYPE (REGNO (x)) == BASIC_INDUCT)
        return reg_biv_class[REGNO (x)]->biv->src_reg;
       break;
-      
+
     default:
       break;
     }