OSDN Git Service

Fix commentary.
[pf3gnuchains/gcc-fork.git] / gcc / unroll.c
index 8737544..aa8f3ee 100644 (file)
@@ -1,5 +1,6 @@
 /* Try to unroll loops, and split induction variables.
-   Copyright (C) 1992, 93, 94, 95, 97, 98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
    Contributed by James E. Wilson, Cygnus Support/UC Berkeley.
 
 This file is part of GNU CC.
@@ -149,11 +150,13 @@ enum unroll_types { UNROLL_COMPLETELY, UNROLL_MODULO, UNROLL_NAIVE };
 #include "config.h"
 #include "system.h"
 #include "rtl.h"
+#include "tm_p.h"
 #include "insn-config.h"
 #include "integrate.h"
 #include "regs.h"
 #include "recog.h"
 #include "flags.h"
+#include "function.h"
 #include "expr.h"
 #include "loop.h"
 #include "toplev.h"
@@ -192,64 +195,71 @@ static int *splittable_regs_updates;
 
 /* Forward declarations.  */
 
-static void init_reg_map PROTO((struct inline_remap *, int));
-static rtx calculate_giv_inc PROTO((rtx, rtx, int));
-static rtx initial_reg_note_copy PROTO((rtx, struct inline_remap *));
-static void final_reg_note_copy PROTO((rtx, struct inline_remap *));
-static void copy_loop_body PROTO((rtx, rtx, struct inline_remap *, rtx, int,
+static void init_reg_map PARAMS ((struct inline_remap *, int));
+static rtx calculate_giv_inc PARAMS ((rtx, rtx, unsigned int));
+static rtx initial_reg_note_copy PARAMS ((rtx, struct inline_remap *));
+static void final_reg_note_copy PARAMS ((rtx, struct inline_remap *));
+static void copy_loop_body PARAMS ((rtx, rtx, struct inline_remap *, rtx, int,
                                  enum unroll_types, rtx, rtx, rtx, rtx));
-static void iteration_info PROTO((rtx, rtx *, rtx *, rtx, rtx));
-static int find_splittable_regs PROTO((enum unroll_types, rtx, rtx, rtx, int,
-                                      unsigned HOST_WIDE_INT));
-static int find_splittable_givs PROTO((struct iv_class *, enum unroll_types,
-                                      rtx, rtx, rtx, int));
-static int reg_dead_after_loop PROTO((rtx, rtx, rtx));
-static rtx fold_rtx_mult_add PROTO((rtx, rtx, rtx, enum machine_mode));
-static int verify_addresses PROTO((struct induction *, rtx, int));
-static rtx remap_split_bivs PROTO((rtx));
+static void iteration_info PARAMS ((const struct loop *, rtx, rtx *, rtx *));
+static int find_splittable_regs PARAMS ((const struct loop *,
+                                        enum unroll_types, rtx, int));
+static int find_splittable_givs PARAMS ((const struct loop *, 
+                                        struct iv_class *, enum unroll_types,
+                                        rtx, int));
+static int reg_dead_after_loop PARAMS ((const struct loop *, rtx));
+static rtx fold_rtx_mult_add PARAMS ((rtx, rtx, rtx, enum machine_mode));
+static int verify_addresses PARAMS ((struct induction *, rtx, int));
+static rtx remap_split_bivs PARAMS ((rtx));
+static rtx find_common_reg_term PARAMS ((rtx, rtx));
+static rtx subtract_reg_term PARAMS ((rtx, rtx));
+static rtx loop_find_equiv_value PARAMS ((const struct loop *, rtx));
 
 /* Try to unroll one loop and split induction variables in the loop.
 
-   The loop is described by the arguments LOOP_END, INSN_COUNT, and
-   LOOP_START.  END_INSERT_BEFORE indicates where insns should be added
-   which need to be executed when the loop falls through.  STRENGTH_REDUCTION_P
-   indicates whether information generated in the strength reduction pass
-   is available.
+   The loop is described by the arguments LOOP and INSN_COUNT.
+   END_INSERT_BEFORE indicates where insns should be added which need
+   to be executed when the loop falls through.  STRENGTH_REDUCTION_P
+   indicates whether information generated in the strength reduction
+   pass is available.
 
    This function is intended to be called from within `strength_reduce'
    in loop.c.  */
 
 void
-unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
-            loop_info, strength_reduce_p)
-     rtx loop_end;
+unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
+     struct loop *loop;
      int insn_count;
-     rtx loop_start;
      rtx end_insert_before;
-     struct loop_info *loop_info;
      int strength_reduce_p;
 {
-  int i, j, temp;
+  int i, j;
+  unsigned int r;
+  unsigned HOST_WIDE_INT temp;
   int unroll_number = 1;
   rtx copy_start, copy_end;
   rtx insn, sequence, pattern, tem;
   int max_labelno, max_insnno;
   rtx insert_before;
   struct inline_remap *map;
-  char *local_label;
+  char *local_label = NULL;
   char *local_regno;
-  int maxregnum;
+  unsigned int max_local_regnum;
+  unsigned int maxregnum;
   rtx exit_label = 0;
   rtx start_label;
   struct iv_class *bl;
   int splitting_not_safe = 0;
-  enum unroll_types unroll_type;
+  enum unroll_types unroll_type = UNROLL_NAIVE;
   int loop_preconditioned = 0;
   rtx safety_label;
   /* This points to the last real insn in the loop, which should be either
      a JUMP_INSN (for conditional jumps) or a BARRIER (for unconditional
      jumps).  */
   rtx last_loop_insn;
+  rtx loop_start = loop->start;
+  rtx loop_end = loop->end;
+  struct loop_info *loop_info = LOOP_INFO (loop);
 
   /* Don't bother unrolling huge loops.  Since the minimum factor is
      two, loops greater than one half of MAX_UNROLLED_INSNS will never
@@ -283,6 +293,19 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
                block_begins++;
              else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
                block_ends++;
+             if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
+                 || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
+               {
+                 /* Note, would be nice to add code to unroll EH
+                    regions, but until that time, we punt (don't
+                    unroll).  For the proper way of doing it, see
+                    expand_inline_function.  */
+
+                 if (loop_dump_stream)
+                   fprintf (loop_dump_stream,
+                            "Unrolling failure: cannot unroll EH regions.\n");
+                 return;
+               }
            }
        }
 
@@ -338,20 +361,31 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
       else if (GET_CODE (last_loop_insn) == JUMP_INSN)
        {
 #ifdef HAVE_cc0
-         /* The immediately preceding insn is a compare which must be
-            deleted.  */
-         delete_insn (last_loop_insn);
-         delete_insn (PREV_INSN (last_loop_insn));
-#else
-         /* The immediately preceding insn may not be the compare, so don't
-            delete it.  */
+         rtx prev = PREV_INSN (last_loop_insn);
+#endif
          delete_insn (last_loop_insn);
+#ifdef HAVE_cc0
+         /* The immediately preceding insn may be a compare which must be
+            deleted.  */
+         if (sets_cc0_p (prev))
+           delete_insn (prev);
 #endif
        }
+
+      /* Remove the loop notes since this is no longer a loop.  */
+      if (loop->vtop)
+       delete_insn (loop->vtop);
+      if (loop->cont)
+       delete_insn (loop->cont);
+      if (loop_start)
+       delete_insn (loop_start);
+      if (loop_end)
+       delete_insn (loop_end);
+
       return;
     }
   else if (loop_info->n_iterations > 0
-      && loop_info->n_iterations * insn_count < MAX_UNROLLED_INSNS)
+          && loop_info->n_iterations * insn_count < MAX_UNROLLED_INSNS)
     {
       unroll_number = loop_info->n_iterations;
       unroll_type = UNROLL_COMPLETELY;
@@ -405,7 +439,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
   /* Default case, calculate number of times to unroll loop based on its
      size.  */
-  if (unroll_number == 1)
+  if (unroll_type == UNROLL_NAIVE)
     {
       if (8 * insn_count < MAX_UNROLLED_INSNS)
        unroll_number = 8;
@@ -413,8 +447,6 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
        unroll_number = 4;
       else
        unroll_number = 2;
-
-      unroll_type = UNROLL_NAIVE;
     }
 
   /* Now we know how many times to unroll the loop.  */
@@ -477,14 +509,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
        copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
       else if (GET_CODE (last_loop_insn) == JUMP_INSN)
        {
+         copy_end = PREV_INSN (last_loop_insn);
 #ifdef HAVE_cc0
-         /* The instruction immediately before the JUMP_INSN is a compare
+         /* The instruction immediately before the JUMP_INSN may be a compare
             instruction which we do not want to copy.  */
-         copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
-#else
-         /* The instruction immediately before the JUMP_INSN may not be the
-            compare, so we must copy it.  */
-         copy_end = PREV_INSN (last_loop_insn);
+         if (sets_cc0_p (PREV_INSN (copy_end)))
+           copy_end = PREV_INSN (copy_end);
 #endif
        }
       else
@@ -518,17 +548,14 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
        }
       else if (GET_CODE (last_loop_insn) == JUMP_INSN)
        {
+         insert_before = last_loop_insn;
 #ifdef HAVE_cc0
-         /* The instruction immediately before the JUMP_INSN is a compare
+         /* The instruction immediately before the JUMP_INSN may be a compare
             instruction which we do not want to copy or delete.  */
-         insert_before = PREV_INSN (last_loop_insn);
-         copy_end = PREV_INSN (insert_before);
-#else
-         /* The instruction immediately before the JUMP_INSN may not be the
-            compare, so we must copy it.  */
-         insert_before = last_loop_insn;
-         copy_end = PREV_INSN (last_loop_insn);
+         if (sets_cc0_p (PREV_INSN (insert_before)))
+           insert_before = PREV_INSN (insert_before);
 #endif
+         copy_end = PREV_INSN (insert_before);
        }
       else
        {
@@ -648,6 +675,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
   if (unroll_type == UNROLL_NAIVE
       && GET_CODE (last_loop_insn) == BARRIER
+      && GET_CODE (PREV_INSN (last_loop_insn)) == JUMP_INSN
       && start_label != JUMP_LABEL (PREV_INSN (last_loop_insn)))
     {
       /* In this case, we must copy the jump and barrier, because they will
@@ -680,22 +708,20 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   max_labelno = max_label_num ();
   max_insnno = get_max_uid ();
 
-  map = (struct inline_remap *) alloca (sizeof (struct inline_remap));
+  /* Various paths through the unroll code may reach the "egress" label
+     without initializing fields within the map structure.
 
-  map->integrating = 0;
-  map->const_equiv_varray = 0;
+     To be safe, we use xcalloc to zero the memory.  */
+  map = (struct inline_remap *) xcalloc (1, sizeof (struct inline_remap));
 
   /* Allocate the label map.  */
 
   if (max_labelno > 0)
     {
-      map->label_map = (rtx *) alloca (max_labelno * sizeof (rtx));
+      map->label_map = (rtx *) xmalloc (max_labelno * sizeof (rtx));
 
-      local_label = (char *) alloca (max_labelno);
-      bzero (local_label, max_labelno);
+      local_label = (char *) xcalloc (max_labelno, sizeof (char));
     }
-  else
-    map->label_map = 0;
 
   /* Search the loop and mark all local labels, i.e. the ones which have to
      be distinct labels when copied.  For all labels which might be
@@ -740,7 +766,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
   /* Allocate space for the insn map.  */
 
-  map->insn_map = (rtx *) alloca (max_insnno * sizeof (rtx));
+  map->insn_map = (rtx *) xmalloc (max_insnno * sizeof (rtx));
 
   /* Set this to zero, to indicate that we are doing loop unrolling,
      not function inlining.  */
@@ -755,6 +781,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.
@@ -763,78 +792,81 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
      preconditioning code and find_splittable_regs will never be used
      to access the splittable_regs[] and addr_combined_regs[] arrays.  */
 
-  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));
+  splittable_regs = (rtx *) xcalloc (maxregnum, sizeof (rtx));
+  derived_regs = (char *) xcalloc (maxregnum, sizeof (char));
+  splittable_regs_updates = (int *) xcalloc (maxregnum, sizeof (int));
   addr_combined_regs
-    = (struct induction **) alloca (maxregnum * sizeof (struct induction *));
-  bzero ((char *) addr_combined_regs, maxregnum * sizeof (struct induction *));
-  local_regno = (char *) alloca (maxregnum);
-  bzero (local_regno, maxregnum);
+    = (struct induction **) xcalloc (maxregnum, sizeof (struct induction *));
+  local_regno = (char *) xcalloc (maxregnum, sizeof (char));
 
   /* Mark all local registers, i.e. the ones which are referenced only
      inside the loop.  */
   if (INSN_UID (copy_end) < max_uid_for_loop)
-  {
-    int copy_start_luid = INSN_LUID (copy_start);
-    int copy_end_luid = INSN_LUID (copy_end);
-
-    /* If a register is used in the jump insn, we must not duplicate it
-       since it will also be used outside the loop.  */
-    if (GET_CODE (copy_end) == JUMP_INSN)
-      copy_end_luid--;
-    /* If copy_start points to the NOTE that starts the loop, then we must
-       use the next luid, because invariant pseudo-regs moved out of the loop
-       have their lifetimes modified to start here, but they are not safe
-       to duplicate.  */
-    if (copy_start == loop_start)
-      copy_start_luid++;
-
-    /* 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
-         && REGNO_LAST_UID (j) > 0 && REGNO_LAST_UID (j) <= max_uid_for_loop
-         && uid_luid[REGNO_LAST_UID (j)] <= copy_end_luid)
-       {
-         /* However, we must also check for loop-carried dependencies.
-            If the value the pseudo has at the end of iteration X is
-            used by iteration X+1, then we can not use a different pseudo
-            for each unrolled copy of the loop.  */
-         /* A pseudo is safe if regno_first_uid is a set, and this
-            set dominates all instructions from regno_first_uid to
-            regno_last_uid.  */
-         /* ??? This check is simplistic.  We would get better code if
-            this check was more sophisticated.  */
-         if (set_dominates_use (j, REGNO_FIRST_UID (j), REGNO_LAST_UID (j),
-                                copy_start, copy_end))
-           local_regno[j] = 1;
+    {
+      int copy_start_luid = INSN_LUID (copy_start);
+      int copy_end_luid = INSN_LUID (copy_end);
 
+      /* If a register is used in the jump insn, we must not duplicate it
+        since it will also be used outside the loop.  */
+      if (GET_CODE (copy_end) == JUMP_INSN)
+       copy_end_luid--;
+
+      /* If we have a target that uses cc0, then we also must not duplicate
+        the insn that sets cc0 before the jump insn, if one is present.  */
+#ifdef HAVE_cc0
+      if (GET_CODE (copy_end) == JUMP_INSN && sets_cc0_p (PREV_INSN (copy_end)))
+       copy_end_luid--;
+#endif
+
+      /* If copy_start points to the NOTE that starts the loop, then we must
+        use the next luid, because invariant pseudo-regs moved out of the loop
+        have their lifetimes modified to start here, but they are not safe
+        to duplicate.  */
+      if (copy_start == loop_start)
+       copy_start_luid++;
+
+      /* 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 (r = FIRST_PSEUDO_REGISTER; r < max_reg_before_loop; ++r)
+       if (REGNO_FIRST_UID (r) > 0 && REGNO_FIRST_UID (r) <= max_uid_for_loop
+           && uid_luid[REGNO_FIRST_UID (r)] >= copy_start_luid
+           && REGNO_LAST_UID (r) > 0 && REGNO_LAST_UID (r) <= max_uid_for_loop
+           && uid_luid[REGNO_LAST_UID (r)] <= copy_end_luid)
+         {
+           /* However, we must also check for loop-carried dependencies.
+              If the value the pseudo has at the end of iteration X is
+              used by iteration X+1, then we can not use a different pseudo
+              for each unrolled copy of the loop.  */
+           /* A pseudo is safe if regno_first_uid is a set, and this
+              set dominates all instructions from regno_first_uid to
+              regno_last_uid.  */
+           /* ??? This check is simplistic.  We would get better code if
+              this check was more sophisticated.  */
+           if (set_dominates_use (r, REGNO_FIRST_UID (r), REGNO_LAST_UID (r),
+                                  copy_start, copy_end))
+             local_regno[r] = 1;
+
+           if (loop_dump_stream)
+             {
+               if (local_regno[r])
+                 fprintf (loop_dump_stream, "Marked reg %d as local\n", r);
+               else
+                 fprintf (loop_dump_stream, "Did not mark reg %d as local\n",
+                          r);
+             }
+         }
+      /* Givs that have been created from multiple biv increments always have
+        local registers.  */
+      for (r = first_increment_giv; r <= last_increment_giv; r++)
+       {
+         local_regno[r] = 1;
          if (loop_dump_stream)
-           {
-             if (local_regno[j])
-               fprintf (loop_dump_stream, "Marked reg %d as local\n", j);
-             else
-               fprintf (loop_dump_stream, "Did not mark reg %d as local\n",
-                        j);
-           }
+           fprintf (loop_dump_stream, "Marked reg %d as local\n", r);
        }
-    /* 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
      can precondition the loop so as to make the exit tests unnecessary.
@@ -863,7 +895,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
       rtx initial_value, final_value, increment;
       enum machine_mode mode;
 
-      if (precondition_loop_p (loop_start, loop_info,
+      if (precondition_loop_p (loop,
                               &initial_value, &final_value, &increment,
                               &mode))
        {
@@ -871,7 +903,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
          rtx *labels;
          int abs_inc, neg_inc;
 
-         map->reg_map = (rtx *) alloca (maxregnum * sizeof (rtx));
+         map->reg_map = (rtx *) xmalloc (maxregnum * sizeof (rtx));
 
          VARRAY_CONST_EQUIV_INIT (map->const_equiv_varray, maxregnum,
                                   "unroll_loop");
@@ -917,7 +949,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
          /* Now emit a sequence of branches to jump to the proper precond
             loop entry point.  */
 
-         labels = (rtx *) alloca (sizeof (rtx) * unroll_number);
+         labels = (rtx *) xmalloc (sizeof (rtx) * unroll_number);
          for (i = 0; i < unroll_number; i++)
            labels[i] = gen_label_rtx ();
 
@@ -1023,14 +1055,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
            copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
          else if (GET_CODE (last_loop_insn) == JUMP_INSN)
            {
+             copy_end = PREV_INSN (last_loop_insn);
 #ifdef HAVE_cc0
-             /* The immediately preceding insn is a compare which we do not
+             /* The immediately preceding insn may be a compare which we do not
                 want to copy.  */
-             copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
-#else
-             /* The immediately preceding insn may not be a compare, so we
-                must copy it.  */
-             copy_end = PREV_INSN (last_loop_insn);
+             if (sets_cc0_p (PREV_INSN (copy_end)))
+               copy_end = PREV_INSN (copy_end);
 #endif
            }
          else
@@ -1051,12 +1081,13 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
                if (local_label[j])
                  set_label_in_map (map, j, gen_label_rtx ());
 
-             for (j = FIRST_PSEUDO_REGISTER; j < maxregnum; j++)
-               if (local_regno[j])
+             for (r = FIRST_PSEUDO_REGISTER; r < max_local_regnum; r++)
+               if (local_regno[r])
                  {
-                   map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
-                   record_base_value (REGNO (map->reg_map[j]),
-                                      regno_reg_rtx[j], 0);
+                   map->reg_map[r]
+                     = gen_reg_rtx (GET_MODE (regno_reg_rtx[r]));
+                   record_base_value (REGNO (map->reg_map[r]),
+                                      regno_reg_rtx[r], 0);
                  }
              /* The last copy needs the compare/branch insns at the end,
                 so reset copy_end here if the loop ends with a conditional
@@ -1085,22 +1116,22 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
            }
          else
            {
-#ifdef HAVE_cc0
-             /* The immediately preceding insn is a compare which we do not
-                want to copy.  */
-             insert_before = PREV_INSN (last_loop_insn);
-             copy_end = PREV_INSN (insert_before);
-#else
-             /* The immediately preceding insn may not be a compare, so we
-                must copy it.  */
              insert_before = last_loop_insn;
-             copy_end = PREV_INSN (last_loop_insn);
+#ifdef HAVE_cc0
+             /* The instruction immediately before the JUMP_INSN may be a compare
+                instruction which we do not want to copy or delete.  */
+             if (sets_cc0_p (PREV_INSN (insert_before)))
+               insert_before = PREV_INSN (insert_before);
 #endif
+             copy_end = PREV_INSN (insert_before);
            }
 
          /* Set unroll type to MODULO now.  */
          unroll_type = UNROLL_MODULO;
          loop_preconditioned = 1;
+
+         /* Clean up.  */
+         free (labels);
        }
     }
 
@@ -1116,11 +1147,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   /* At this point, we are guaranteed to unroll the loop.  */
 
   /* Keep track of the unroll factor for the loop.  */
-  if (unroll_type == UNROLL_COMPLETELY)
-    loop_info->unroll_number = -1;
-  else
-    loop_info->unroll_number = unroll_number;
-
+  loop_info->unroll_number = unroll_number;
 
   /* For each biv and giv, determine whether it can be safely split into
      a different variable for each unrolled copy of the loop body.
@@ -1133,16 +1160,15 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   if (splitting_not_safe)
     temp = 0;
   else
-    temp = find_splittable_regs (unroll_type, loop_start, loop_end,
-                                end_insert_before, unroll_number,
-                                loop_info->n_iterations);
+    temp = find_splittable_regs (loop, unroll_type,
+                                end_insert_before, unroll_number);
 
   /* find_splittable_regs may have created some new registers, so must
      reallocate the reg_map with the new larger size, and must realloc
      the constant maps also.  */
 
   maxregnum = max_reg_num ();
-  map->reg_map = (rtx *) alloca (maxregnum * sizeof (rtx));
+  map->reg_map = (rtx *) xmalloc (maxregnum * sizeof (rtx));
 
   init_reg_map (map, maxregnum);
 
@@ -1168,8 +1194,8 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
     }
 
   /* Use our current register alignment and pointer flags.  */
-  map->regno_pointer_flag = regno_pointer_flag;
-  map->regno_pointer_align = regno_pointer_align;
+  map->regno_pointer_flag = cfun->emit->regno_pointer_flag;
+  map->regno_pointer_align = cfun->emit->regno_pointer_align;
 
   /* If the loop is being partially unrolled, and the iteration variables
      are being split, and are being renamed for the split, then must fix up
@@ -1199,12 +1225,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
        if (local_label[j])
          set_label_in_map (map, j, gen_label_rtx ());
 
-      for (j = FIRST_PSEUDO_REGISTER; j < maxregnum; j++)
-       if (local_regno[j])
+      for (r = FIRST_PSEUDO_REGISTER; r < max_local_regnum; r++)
+       if (local_regno[r])
          {
-           map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
-           record_base_value (REGNO (map->reg_map[j]),
-                              regno_reg_rtx[j], 0);
+           map->reg_map[r] = gen_reg_rtx (GET_MODE (regno_reg_rtx[r]));
+           record_base_value (REGNO (map->reg_map[r]),
+                              regno_reg_rtx[r], 0);
          }
 
       /* If loop starts with a branch to the test, then fix it so that
@@ -1250,7 +1276,18 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   insn = NEXT_INSN (copy_start);
   while (insn != safety_label)
     {
-      if (insn != start_label)
+      /* ??? Don't delete named code labels.  They will be deleted when the
+        jump that references them is deleted.  Otherwise, we end up deleting
+        them twice, which causes them to completely disappear instead of turn
+        into NOTE_INSN_DELETED_LABEL notes.  This in turn causes aborts in
+        dwarfout.c/dwarf2out.c.  We could perhaps fix the dwarf*out.c files
+        to handle deleted labels instead.  Or perhaps fix DECL_RTL of the
+        associated LABEL_DECL to point to one of the new label instances.  */
+      /* ??? Likewise, we can't delete a NOTE_INSN_DELETED_LABEL note.  */
+      if (insn != start_label
+         && ! (GET_CODE (insn) == CODE_LABEL && LABEL_NAME (insn))
+         && ! (GET_CODE (insn) == NOTE
+               && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL))
        insn = delete_insn (insn);
       else
        insn = NEXT_INSN (insn);
@@ -1271,8 +1308,35 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
     emit_label_after (exit_label, loop_end);
 
  egress:
-  if (map && map->const_equiv_varray)
+  if (unroll_type == UNROLL_COMPLETELY)
+    {
+      /* Remove the loop notes since this is no longer a loop.  */
+      if (loop->vtop)
+       delete_insn (loop->vtop);
+      if (loop->cont)
+       delete_insn (loop->cont);
+      if (loop_start)
+       delete_insn (loop_start);
+      if (loop_end)
+       delete_insn (loop_end);
+    }
+
+  if (map->const_equiv_varray)
     VARRAY_FREE (map->const_equiv_varray);
+  if (map->label_map)
+    {
+      free (map->label_map);
+      free (local_label);
+    }
+  free (map->insn_map);
+  free (splittable_regs);
+  free (derived_regs);
+  free (splittable_regs_updates);
+  free (addr_combined_regs);
+  free (local_regno);
+  if (map->reg_map)
+    free (map->reg_map);
+  free (map);
 }
 \f
 /* Return true if the loop can be safely, and profitably, preconditioned
@@ -1293,13 +1357,13 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
    reflected in RTX_COST.  */
 
 int
-precondition_loop_p (loop_start, loop_info,
-                    initial_value, final_value, increment, mode)
-     rtx loop_start;
-     struct loop_info *loop_info;
+precondition_loop_p (loop, initial_value, final_value, increment, mode)
+     const struct loop *loop;
      rtx *initial_value, *final_value, *increment;
      enum machine_mode *mode;
 {
+  rtx loop_start = loop->start;
+  struct loop_info *loop_info = LOOP_INFO (loop);
 
   if (loop_info->n_iterations > 0)
     {
@@ -1360,16 +1424,16 @@ precondition_loop_p (loop_start, loop_info,
       return 0;
     }
 
-  /* Must ensure that final_value is invariant, so call invariant_p to
-     check.  Before doing so, must check regno against max_reg_before_loop
-     to make sure that the register is in the range covered by invariant_p.
-     If it isn't, then it is most likely a biv/giv which by definition are
-     not invariant.  */
+  /* Must ensure that final_value is invariant, so call
+     loop_invariant_p to check.  Before doing so, must check regno
+     against max_reg_before_loop to make sure that the register is in
+     the range covered by loop_invariant_p.  If it isn't, then it is
+     most likely a biv/giv which by definition are not invariant.  */
   if ((GET_CODE (loop_info->final_value) == REG
        && REGNO (loop_info->final_value) >= max_reg_before_loop)
       || (GET_CODE (loop_info->final_value) == PLUS
          && REGNO (XEXP (loop_info->final_value, 0)) >= max_reg_before_loop)
-      || ! invariant_p (loop_info->final_value))
+      || ! loop_invariant_p (loop, loop_info->final_value))
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -1400,10 +1464,9 @@ 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
@@ -1427,7 +1490,7 @@ precondition_loop_p (loop_start, loop_info,
               < GET_MODE_SIZE (GET_MODE (*initial_value))))
     *mode = GET_MODE (*initial_value);
 
-  /* Success! */
+  /* Success!  */
   if (loop_dump_stream)
     fprintf (loop_dump_stream, "Preconditioning: Successful.\n");
   return 1;
@@ -1471,7 +1534,7 @@ init_reg_map (map, maxregnum)
 static rtx
 calculate_giv_inc (pattern, src_insn, regno)
      rtx pattern, src_insn;
-     int regno;
+     unsigned int regno;
 {
   rtx increment;
   rtx increment_total = 0;
@@ -1602,7 +1665,7 @@ initial_reg_note_copy (notes, map)
   PUT_MODE (copy, GET_MODE (notes));
 
   if (GET_CODE (notes) == EXPR_LIST)
-    XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (notes, 0), map);
+    XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (notes, 0), map, 0);
   else if (GET_CODE (notes) == INSN_LIST)
     /* Don't substitute for these yet.  */
     XEXP (copy, 0) = XEXP (notes, 0);
@@ -1643,7 +1706,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
      rtx start_label, loop_end, insert_before, copy_notes_from;
 {
   rtx insn, pattern;
-  rtx set, tem, copy;
+  rtx set, tem, copy = NULL_RTX;
   int dest_reg_was_split, i;
 #ifdef HAVE_cc0
   rtx cc0_insn = 0;
@@ -1668,6 +1731,12 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
 
   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
     {
@@ -1696,7 +1765,7 @@ 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));
+             unsigned int regno = REGNO (SET_DEST (set));
 
              v = addr_combined_regs[REGNO (SET_DEST (set))];
              bl = reg_biv_class[REGNO (v->src_reg)];
@@ -1757,11 +1826,14 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                            value = plus_constant (tv->dest_reg,
                                                   tv->const_adjust);
 
-                           /* The constant could be too large for an add
-                              immediate, so can't directly emit an insn
-                              here.  */
-                           emit_unrolled_add (dest_reg, XEXP (value, 0),
-                                              XEXP (value, 1));
+                           if (GET_CODE (value) == PLUS)
+                             {
+                               /* The constant could be too large for an add
+                                  immediate, so can't directly emit an insn
+                                  here.  */
+                               emit_unrolled_add (dest_reg, XEXP (value, 0),
+                                                  XEXP (value, 1));
+                             }
                          }
 
                        /* Reset the giv to be just the register again, in case
@@ -1786,8 +1858,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
              && GET_CODE (SET_DEST (set)) == REG
              && splittable_regs[REGNO (SET_DEST (set))])
            {
-             int regno = REGNO (SET_DEST (set));
-             int src_regno;
+             unsigned int regno = REGNO (SET_DEST (set));
+             unsigned int src_regno;
 
              dest_reg_was_split = 1;
 
@@ -1907,7 +1979,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
            }
          else
            {
-             pattern = copy_rtx_and_substitute (pattern, map);
+             pattern = copy_rtx_and_substitute (pattern, map, 0);
              copy = emit_insn (pattern);
            }
          REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map);
@@ -1944,9 +2016,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
             settings which would invalidate this.  */
          if (dest_reg_was_split)
            {
-             int regno = REGNO (SET_DEST (pattern));
+             int regno = REGNO (SET_DEST (set));
 
-             if (regno < VARRAY_SIZE (map->const_equiv_varray)
+             if ((size_t) 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;
@@ -1954,7 +2026,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
          break;
 
        case JUMP_INSN:
-         pattern = copy_rtx_and_substitute (PATTERN (insn), map);
+         pattern = copy_rtx_and_substitute (PATTERN (insn), map, 0);
          copy = emit_jump_insn (pattern);
          REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map);
 
@@ -2060,8 +2132,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
          if (condjump_p (insn) && !simplejump_p (insn) && map->last_pc_value)
            {
 #ifdef HAVE_cc0
-             /* The previous insn set cc0 for us.  So delete it.  */
-             delete_insn (PREV_INSN (copy));
+             /* If the previous insn set cc0 for us, delete it.  */
+             if (sets_cc0_p (PREV_INSN (copy)))
+               delete_insn (PREV_INSN (copy));
 #endif
 
              /* If this is now a no-op, delete it.  */
@@ -2086,14 +2159,15 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
          break;
 
        case CALL_INSN:
-         pattern = copy_rtx_and_substitute (PATTERN (insn), map);
+         pattern = copy_rtx_and_substitute (PATTERN (insn), map, 0);
          copy = emit_call_insn (pattern);
          REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map);
 
          /* Because the USAGE information potentially contains objects other
             than hard registers, we need to copy it.  */
          CALL_INSN_FUNCTION_USAGE (copy)
-           = copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn), map);
+           = copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn),
+                                      map, 0);
 
 #ifdef HAVE_cc0
          if (cc0_insn)
@@ -2124,11 +2198,16 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
          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));
@@ -2138,7 +2217,6 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
 
        default:
          abort ();
-         break;
        }
 
       map->insn_map[INSN_UID (insn)] = copy;
@@ -2171,8 +2249,17 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
     {
       for (insn = copy_notes_from; insn != loop_end; insn = NEXT_INSN (insn))
        {
+         /* VTOP notes are valid only before the loop exit test.
+            If placed anywhere else, loop may generate bad code.
+            There is no need to test for NOTE_INSN_LOOP_CONT notes
+            here, since COPY_NOTES_FROM will be at most one or two (for cc0)
+            instructions before the last insn in the loop, and if the
+            end test is that short, there will be a VTOP note between
+            the CONT note and the test.  */
          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
+             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP)
            emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
        }
     }
@@ -2202,21 +2289,23 @@ emit_unrolled_add (dest_reg, src_reg, increment)
     emit_move_insn (dest_reg, result);
 }
 \f
-/* Searches the insns between INSN and LOOP_END.  Returns 1 if there
+/* Searches the insns between INSN and LOOP->END.  Returns 1 if there
    is a backward branch in that range that branches to somewhere between
-   LOOP_START and INSN.  Returns 0 otherwise.  */
+   LOOP->START and INSN.  Returns 0 otherwise.  */
 
 /* ??? This is quadratic algorithm.  Could be rewritten to be linear.
    In practice, this is not a problem, because this function is seldom called,
    and uses a negligible amount of CPU time on average.  */
 
 int
-back_branch_in_range_p (insn, loop_start, loop_end)
+back_branch_in_range_p (loop, insn)
+     const struct loop *loop;
      rtx insn;
-     rtx loop_start, loop_end;
 {
   rtx p, q, target_insn;
-  rtx orig_loop_end = loop_end;
+  rtx loop_start = loop->start;
+  rtx loop_end = loop->end;
+  rtx orig_loop_end = loop->end;
 
   /* Stop before we get to the backward branch at the end of the loop.  */
   loop_end = prev_nonnote_insn (loop_end);
@@ -2306,9 +2395,8 @@ fold_rtx_mult_add (mult1, mult2, add1, mode)
    if it can be calculated.  Otherwise, returns 0.  */
 
 rtx
-biv_total_increment (bl, loop_start, loop_end)
+biv_total_increment (bl)
      struct iv_class *bl;
-     rtx loop_start, loop_end;
 {
   struct induction *v;
   rtx result;
@@ -2341,14 +2429,11 @@ biv_total_increment (bl, loop_start, loop_end)
    be calculated.  */
 
 static void
-iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
+iteration_info (loop, iteration_var, initial_value, increment)
+     const struct loop *loop ATTRIBUTE_UNUSED;
      rtx iteration_var, *initial_value, *increment;
-     rtx loop_start, loop_end;
 {
   struct iv_class *bl;
-#if 0
-  struct induction *v;
-#endif
 
   /* Clear the result values, in case no answer can be found.  */
   *initial_value = 0;
@@ -2360,7 +2445,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 ((unsigned) REGNO (iteration_var) > reg_iv_type->num_elements)
+  if ((unsigned) REGNO (iteration_var) >= reg_iv_type->num_elements)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -2388,42 +2473,60 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
     }
   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);
+      *increment = biv_total_increment (bl);
     }
   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));
+      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);
+      *increment = biv_total_increment (bl);
       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
     {
@@ -2460,13 +2563,11 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
    times, since multiplies by small integers (1,2,3,4) are very cheap.  */
 
 static int
-find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
-                    unroll_number, n_iterations)
+find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
+     const struct loop *loop;
      enum unroll_types unroll_type;
-     rtx loop_start, loop_end;
      rtx end_insert_before;
      int unroll_number;
-     unsigned HOST_WIDE_INT n_iterations;
 {
   struct iv_class *bl;
   struct induction *v;
@@ -2474,13 +2575,15 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
   rtx biv_final_value;
   int biv_splittable;
   int result = 0;
+  rtx loop_start = loop->start;
+  rtx loop_end = loop->end;
 
   for (bl = loop_iv_list; bl; bl = bl->next)
     {
       /* Biv_total_increment must return a constant value,
         otherwise we can not calculate the split values.  */
 
-      increment = biv_total_increment (bl, loop_start, loop_end);
+      increment = biv_total_increment (bl);
       if (! increment || GET_CODE (increment) != CONST_INT)
        continue;
 
@@ -2496,16 +2599,14 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
       biv_splittable = 1;
       biv_final_value = 0;
       if (unroll_type != UNROLL_COMPLETELY
-         && (loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]]
-             || unroll_type == UNROLL_NAIVE)
+         && (loop->exit_count || unroll_type == UNROLL_NAIVE)
          && (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))
              || reg_mentioned_p (bl->biv->dest_reg, SET_SRC (bl->init_set)))
-         && ! (biv_final_value = final_biv_value (bl, loop_start, loop_end,
-                                                  n_iterations)))
+         && ! (biv_final_value = final_biv_value (loop, bl)))
        biv_splittable = 0;
 
       /* If any of the insns setting the BIV don't do so with a simple
@@ -2537,7 +2638,7 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
              if (GET_CODE (bl->initial_value) == REG
                  && (REGNO (bl->initial_value) == bl->regno
                      || REGNO (bl->initial_value) < FIRST_PSEUDO_REGISTER
-                     || ! invariant_p (bl->initial_value)))
+                     || ! loop_invariant_p (loop, bl->initial_value)))
                {
                  rtx tem = gen_reg_rtx (bl->biv->mode);
 
@@ -2573,8 +2674,8 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
         depend on it may be splittable if the biv is live outside the
         loop, and the givs aren't.  */
 
-      result += find_splittable_givs (bl, unroll_type, loop_start, loop_end,
-                                    increment, unroll_number);
+      result += find_splittable_givs (loop, bl, unroll_type, increment, 
+                                     unroll_number);
 
       /* If final value is non-zero, then must emit an instruction which sets
         the value of the biv to the proper value.  This is done after
@@ -2586,7 +2687,7 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
             loop to ensure that it will always be executed no matter
             how the loop exits.  Otherwise emit the insn after the loop,
             since this is slightly more efficient.  */
-         if (! loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]])
+         if (! loop->exit_count)
            emit_insn_before (gen_move_insn (bl->biv->src_reg,
                                             biv_final_value),
                              end_insert_before);
@@ -2654,11 +2755,10 @@ verify_addresses (v, giv_inc, unroll_number)
    Return the number of instructions that set splittable registers.  */
 
 static int
-find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
-                     unroll_number)
+find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
+     const struct loop *loop;
      struct iv_class *bl;
      enum unroll_types unroll_type;
-     rtx loop_start, loop_end;
      rtx increment;
      int unroll_number;
 {
@@ -2692,7 +2792,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
         won't reach here if they aren't.  */
       if (v->giv_type != DEST_ADDR
          && (! v->always_computable
-             || back_branch_in_range_p (v->insn, loop_start, loop_end)))
+             || back_branch_in_range_p (loop, v->insn)))
        continue;
 
       /* The giv increment value must be a constant.  */
@@ -2713,8 +2813,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
 
       final_value = 0;
       if (unroll_type != UNROLL_COMPLETELY
-         && (loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]]
-             || unroll_type == UNROLL_NAIVE)
+         && (loop->exit_count || unroll_type == UNROLL_NAIVE)
          && v->giv_type != DEST_ADDR
          /* The next part is true if the pseudo is used outside the loop.
             We assume that this is true for any pseudo created after loop
@@ -2729,7 +2828,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                          != INSN_UID (XEXP (tem, 0)))))
              /* Line above always fails if INSN was moved by loop opt.  */
              || (uid_luid[REGNO_LAST_UID (REGNO (v->dest_reg))]
-                 >= INSN_LUID (loop_end)))
+                 >= 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
@@ -2787,7 +2886,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
 
              record_base_value (REGNO (tem), bl->biv->add_val, 0);
              emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
-                               loop_start);
+                               loop->start);
              biv_initial_value = tem;
            }
          value = fold_rtx_mult_add (v->mult_val, biv_initial_value,
@@ -2829,7 +2928,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                  rtx tem = gen_reg_rtx (v->mode);
                  record_base_value (REGNO (tem), v->add_val, 0);
                  emit_iv_add_mult (bl->initial_value, v->mult_val,
-                                   v->add_val, tem, loop_start);
+                                   v->add_val, tem, loop->start);
                  value = tem;
                }
 
@@ -2978,8 +3077,8 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                     to calculate the value from scratch.  */
                  emit_insn_before (gen_rtx_SET (VOIDmode, tem,
                                                 copy_rtx (v->new_reg)),
-                                   loop_start);
-                 if (recog_memoized (PREV_INSN (loop_start)) < 0)
+                                   loop->start);
+                 if (recog_memoized (PREV_INSN (loop->start)) < 0)
                    {
                      rtx sequence, ret;
 
@@ -2987,7 +3086,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                         value, because the loop may have been preconditioned.
                         We must calculate it from NEW_REG.  Try using
                         force_operand instead of emit_iv_add_mult.  */
-                     delete_insn (PREV_INSN (loop_start));
+                     delete_insn (PREV_INSN (loop->start));
 
                      start_sequence ();
                      ret = force_operand (v->new_reg, tem);
@@ -2995,7 +3094,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                        emit_move_insn (tem, ret);
                      sequence = gen_sequence ();
                      end_sequence ();
-                     emit_insn_before (sequence, loop_start);
+                     emit_insn_before (sequence, loop->start);
 
                      if (loop_dump_stream)
                        fprintf (loop_dump_stream,
@@ -3134,32 +3233,31 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
    it can search past if statements and other similar structures.  */
 
 static int
-reg_dead_after_loop (reg, loop_start, loop_end)
-     rtx reg, loop_start, loop_end;
+reg_dead_after_loop (loop, reg)
+     const struct loop *loop;
+     rtx reg;
 {
   rtx insn, label;
   enum rtx_code code;
   int jump_count = 0;
   int label_count = 0;
-  int this_loop_num = uid_loop_num[INSN_UID (loop_start)];
 
   /* In addition to checking all exits of this loop, we must also check
      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))
+  for (label = loop->exit_labels; label; label = LABEL_NEXTREF (label))
     label_count++;
 
-  if (label_count != loop_number_exit_count[this_loop_num])
+  if (label_count != loop->exit_count)
     return 0;
 
   /* HACK: Must also search the loop fall through exit, create a label_ref
-     here which points to the loop_end, and append the loop_number_exit_labels
+     here which points to the loop->end, and append the loop_number_exit_labels
      list to it.  */
-  label = gen_rtx_LABEL_REF (VOIDmode, loop_end);
-  LABEL_NEXTREF (label) = loop_number_exit_labels[this_loop_num];
+  label = gen_rtx_LABEL_REF (VOIDmode, loop->end);
+  LABEL_NEXTREF (label) = loop->exit_labels;
 
   for ( ; label; label = LABEL_NEXTREF (label))
     {
@@ -3207,11 +3305,12 @@ reg_dead_after_loop (reg, loop_start, loop_end)
    the end of the loop.  If we can do it, return that value.  */
 
 rtx
-final_biv_value (bl, loop_start, loop_end, n_iterations)
+final_biv_value (loop, bl)
+     const struct loop *loop;
      struct iv_class *bl;
-     rtx loop_start, loop_end;
-     unsigned HOST_WIDE_INT n_iterations;
 {
+  rtx loop_end = loop->end;
+  unsigned HOST_WIDE_INT n_iterations = LOOP_INFO (loop)->n_iterations;
   rtx increment, tem;
 
   /* ??? This only works for MODE_INT biv's.  Reject all others for now.  */
@@ -3239,12 +3338,12 @@ final_biv_value (bl, loop_start, loop_end, n_iterations)
      value of the biv must be invariant.  */
 
   if (n_iterations != 0
-      && ! loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]]
-      && invariant_p (bl->initial_value))
+      && ! loop->exit_count
+      && loop_invariant_p (loop, bl->initial_value))
     {
-      increment = biv_total_increment (bl, loop_start, loop_end);
+      increment = biv_total_increment (bl);
 
-      if (increment && invariant_p (increment))
+      if (increment && loop_invariant_p (loop, increment))
        {
          /* Can calculate the loop exit value, emit insns after loop
             end to calculate this value into a temporary register in
@@ -3267,7 +3366,7 @@ final_biv_value (bl, loop_start, loop_end, n_iterations)
     }
 
   /* Check to see if the biv is dead at all loop exits.  */
-  if (reg_dead_after_loop (bl->biv->src_reg, loop_start, loop_end))
+  if (reg_dead_after_loop (loop, bl->biv->src_reg))
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -3284,15 +3383,16 @@ final_biv_value (bl, loop_start, loop_end, n_iterations)
    the end of the loop.  If we can do it, return that value.  */
 
 rtx
-final_giv_value (v, loop_start, loop_end, n_iterations)
+final_giv_value (loop, v)
+     const struct loop *loop;
      struct induction *v;
-     rtx loop_start, loop_end;
-     unsigned HOST_WIDE_INT n_iterations;
 {
   struct iv_class *bl;
   rtx insn;
   rtx increment, tem;
   rtx insert_before, seq;
+  rtx loop_end = loop->end;
+  unsigned HOST_WIDE_INT n_iterations = LOOP_INFO (loop)->n_iterations;
 
   bl = reg_biv_class[REGNO (v->src_reg)];
 
@@ -3319,7 +3419,7 @@ final_giv_value (v, loop_start, loop_end, n_iterations)
      to be known.  */
 
   if (n_iterations != 0
-      && ! loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]])
+      && ! loop->exit_count)
     {
       /* ?? It is tempting to use the biv's value here since these insns will
         be put after the loop, and hence the biv will have its final value
@@ -3332,10 +3432,10 @@ final_giv_value (v, loop_start, loop_end, n_iterations)
         sure that bl->initial_value is still valid then.  It will still
         be valid if it is invariant.  */
 
-      increment = biv_total_increment (bl, loop_start, loop_end);
+      increment = biv_total_increment (bl);
 
-      if (increment && invariant_p (increment)
-         && invariant_p (bl->initial_value))
+      if (increment && loop_invariant_p (loop, increment)
+         && loop_invariant_p (loop, bl->initial_value))
        {
          /* Can calculate the loop exit value of its biv as
             (n_iterations * increment) + initial_value */
@@ -3392,7 +3492,7 @@ final_giv_value (v, loop_start, loop_end, n_iterations)
     abort ();
 
   /* Check to see if the biv is dead at all loop exits.  */
-  if (reg_dead_after_loop (v->dest_reg, loop_start, loop_end))
+  if (reg_dead_after_loop (loop, v->dest_reg))
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -3406,15 +3506,16 @@ final_giv_value (v, loop_start, loop_end, n_iterations)
 }
 
 
-/* Look back before LOOP_START for then insn that sets REG and return
+/* Look back before LOOP->START for then insn that sets REG and return
    the equivalent constant if there is a REG_EQUAL note otherwise just
    the SET_SRC of REG.  */
 
 static rtx
-loop_find_equiv_value (loop_start, reg)
-     rtx loop_start;
+loop_find_equiv_value (loop, reg)
+     const struct loop *loop;
      rtx reg;
 {
+  rtx loop_start = loop->start;
   rtx insn, set;
   rtx ret;
 
@@ -3450,7 +3551,6 @@ loop_find_equiv_value (loop_start, reg)
   return ret;
 }
 
-
 /* 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
@@ -3516,14 +3616,12 @@ find_common_reg_term (op0, op1)
   return NULL_RTX;
 }
 
-
 /* Calculate the number of loop iterations.  Returns the exact number of loop
    iterations if it can be calculated, otherwise returns zero.  */
 
 unsigned HOST_WIDE_INT
-loop_iterations (loop_start, loop_end, loop_info)
-     rtx loop_start, loop_end;
-     struct loop_info *loop_info;
+loop_iterations (loop)
+     struct loop *loop;
 {
   rtx comparison, comparison_value;
   rtx iteration_var, initial_value, increment, final_value;
@@ -3534,8 +3632,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;
+  struct loop_info *loop_info = LOOP_INFO (loop);
 
   loop_info->n_iterations = 0;
   loop_info->initial_value = 0;
@@ -3546,13 +3644,12 @@ 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;
 
   /* 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);
+  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
@@ -3579,7 +3676,7 @@ loop_iterations (loop_start, loop_end, loop_info)
      branch, and the insn before tests a register value, make that the
      iteration variable.  */
 
-  comparison = get_condition_for_loop (last_loop_insn);
+  comparison = get_condition_for_loop (loop, last_loop_insn);
   if (comparison == 0)
     {
       if (loop_dump_stream)
@@ -3595,25 +3692,6 @@ 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)
@@ -3622,14 +3700,18 @@ 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 are created before loop iterations
+     are givs made from biv increments or registers created by
+     load_mems.  In the latter case, it is possible that try_copy_prop
+     will propagate a new pseudo into the old iteration register but
+     this will be marked by having the REG_USERVAR_P bit set.  */
 
-  if (REGNO (iteration_var) >= max_reg_before_loop)
+  if ((unsigned) REGNO (iteration_var) >= reg_iv_type->num_elements
+      && ! REG_USERVAR_P (iteration_var))
     abort ();
 
-  iteration_info (iteration_var, &initial_value, &increment,
-                 loop_start, loop_end);
+  iteration_info (loop, iteration_var, &initial_value, &increment);
+
   if (initial_value == 0)
     /* iteration_info already printed a message.  */
     return 0;
@@ -3674,12 +3756,14 @@ loop_iterations (loop_start, loop_end, loop_info)
      its value from the insns before the start of the loop.  */
 
   final_value = comparison_value;
-  if (GET_CODE (comparison_value) == REG && invariant_p (comparison_value))
+  if (GET_CODE (comparison_value) == REG 
+      && loop_invariant_p (loop, comparison_value))
     {
-      final_value = loop_find_equiv_value (loop_start, comparison_value);
+      final_value = loop_find_equiv_value (loop, comparison_value);
+
       /* If we don't get an invariant final value, we are better
         off with the original register.  */
-      if (!invariant_p (final_value))
+      if (! loop_invariant_p (loop, final_value))
        final_value = comparison_value;
     }
 
@@ -3736,7 +3820,8 @@ loop_iterations (loop_start, loop_end, loop_info)
 
          /* 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);
+         temp = loop_find_equiv_value (loop, reg1);
+
          if (find_common_reg_term (temp, reg2))
            initial_value = temp;
          else
@@ -3744,7 +3829,8 @@ loop_iterations (loop_start, loop_end, loop_info)
              /* 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);
+             temp = loop_find_equiv_value (loop, reg2);
+
              if (temp == loop_info->iteration_var)
                temp = initial_value;
              if (temp == reg1)
@@ -3752,7 +3838,7 @@ loop_iterations (loop_start, loop_end, loop_info)
                  ? reg1 : gen_rtx_PLUS (GET_MODE (reg1), reg1, const2);
            }
        }
-      else if (loop_info->vtop && GET_CODE (reg2) == CONST_INT)
+      else if (loop->vtop && GET_CODE (reg2) == CONST_INT)
        {
          rtx temp;
 
@@ -3763,10 +3849,12 @@ loop_iterations (loop_start, loop_end, loop_info)
              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);
+         temp = loop_find_equiv_value (loop, reg1);
+
          if (GET_CODE (temp) == MINUS && REG_P (XEXP (temp, 0)))
            {
-             rtx temp2 = loop_find_equiv_value (loop_start, XEXP (temp, 0));
+             rtx temp2 = loop_find_equiv_value (loop, XEXP (temp, 0));
+
              if (GET_CODE (temp2) == PLUS
                  && XEXP (temp2, 0) == XEXP (temp, 1))
                initial_value = XEXP (temp2, 1);
@@ -3783,7 +3871,7 @@ loop_iterations (loop_start, loop_end, loop_info)
 
      ??? Without a vtop we could still perform the optimization if we check
      the initial and final values carefully.  */
-  if (loop_info->vtop
+  if (loop->vtop
       && (reg_term = find_common_reg_term (initial_value, final_value)))
     {
       initial_value = subtract_reg_term (initial_value, reg_term);
@@ -3793,6 +3881,12 @@ loop_iterations (loop_start, loop_end, loop_info)
   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)
@@ -3803,7 +3897,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, increment);
 
       if (GET_CODE (increment) != CONST_INT)
        {
@@ -3946,7 +4044,7 @@ remap_split_bivs (x)
 {
   register enum rtx_code code;
   register int i;
-  register char *fmt;
+  register const char *fmt;
 
   if (x == 0)
     return x;
@@ -3983,7 +4081,7 @@ remap_split_bivs (x)
     {
       if (fmt[i] == 'e')
        XEXP (x, i) = remap_split_bivs (XEXP (x, i));
-      if (fmt[i] == 'E')
+      else if (fmt[i] == 'E')
        {
          register int j;
          for (j = 0; j < XVECLEN (x, i); j++)