OSDN Git Service

* tree.c (unsave_expr_now): Avoid recursing into the parts of
[pf3gnuchains/gcc-fork.git] / gcc / unroll.c
index 7d4e2d9..74e54bd 100644 (file)
@@ -1,5 +1,5 @@
 /* Try to unroll loops, and split induction variables.
-   Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
    Contributed by James E. Wilson, Cygnus Support/UC Berkeley.
 
 This file is part of GNU CC.
@@ -16,7 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* Try to unroll a loop, and split induction variables.
 
@@ -190,18 +191,25 @@ static rtx loop_iteration_var;
 static rtx loop_initial_value;
 static rtx loop_increment;
 static rtx loop_final_value;
+static enum rtx_code loop_comparison_code;
 
 /* Forward declarations.  */
 
-static void init_reg_map ();
-static int precondition_loop_p ();
-static void copy_loop_body ();
-static void iteration_info ();
-static rtx approx_final_value ();
-static int find_splittable_regs ();
-static int find_splittable_givs ();
-static rtx fold_rtx_mult_add ();
-static rtx remap_split_bivs ();
+static void init_reg_map PROTO((struct inline_remap *, int));
+static int precondition_loop_p PROTO((rtx *, rtx *, rtx *, rtx, rtx));
+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,
+                                 enum unroll_types, rtx, rtx, rtx, rtx));
+static void iteration_info PROTO((rtx, rtx *, rtx *, rtx, rtx));
+static rtx approx_final_value PROTO((enum rtx_code, rtx, int *, int *));
+static int find_splittable_regs PROTO((enum unroll_types, rtx, rtx, rtx, 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 rtx remap_split_bivs PROTO((rtx));
 
 /* Try to unroll one loop and split induction variables in the loop.
 
@@ -231,6 +239,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   rtx insert_before;
   struct inline_remap *map;
   char *local_label;
+  char *local_regno;
   int maxregnum;
   int new_maxregnum;
   rtx exit_label = 0;
@@ -259,8 +268,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
      of block_beg and block_end notes, because that would unbalance the block
      structure of the function.  This can happen as a result of the
      "if (foo) bar; else break;" optimization in jump.c.  */
+  /* ??? Gcc has a general policy that -g is never supposed to change the code
+     that the compiler emits, so we must disable this optimization always,
+     even if debug info is not being output.  This is rare, so this should
+     not be a significant performance problem.  */
 
-  if (write_symbols != NO_DEBUG)
+  if (1 /* write_symbols != NO_DEBUG */)
     {
       int block_begins = 0;
       int block_ends = 0;
@@ -624,6 +637,23 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
       copy_end = last_loop_insn;
     }
 
+  if (unroll_type == UNROLL_NAIVE
+      && GET_CODE (last_loop_insn) == JUMP_INSN
+      && start_label != JUMP_LABEL (last_loop_insn))
+    {
+      /* ??? The loop ends with a conditional branch that does not branch back
+        to the loop start label.  In this case, we must emit an unconditional
+        branch to the loop exit after emitting the final branch.
+        copy_loop_body does not have support for this currently, so we
+        give up.  It doesn't seem worthwhile to unroll anyways since
+        unrolling would increase the number of branch instructions
+        executed.  */
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Unrolling failure: final conditional branch not to loop start\n");
+      return;
+    }
+
   /* Allocate a translation table for the labels and insn numbers.
      They will be filled in as we copy the insns in the loop.  */
 
@@ -711,6 +741,62 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   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);
+
+  /* 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.  */
+    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;
+
+         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);
+           }
+       }
+  }
 
   /* 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.
@@ -814,6 +900,24 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
          for (i = 0; i < unroll_number; i++)
            labels[i] = gen_label_rtx ();
 
+         /* Check for the case where the initial value is greater than or
+            equal to the final value.  In that case, we want to execute
+            exactly one loop iteration.  The code below will fail for this
+            case.  This check does not apply if the loop has a NE
+            comparison at the end.  */
+
+         if (loop_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]));
+             JUMP_LABEL (get_last_insn ()) = labels[1];
+             LABEL_NUSES (labels[1])++;
+           }
+
          /* Assuming the unroll_number is 4, and the increment is 2, then
             for a negative increment:  for a positive increment:
             diff = 0,1   precond 0     diff = 0,7   precond 0
@@ -830,18 +934,28 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
          for (i = 0; i < unroll_number - 1; i++)
            {
              int cmp_const;
+             enum rtx_code cmp_code;
 
              /* For negative increments, must invert the constant compared
                 against, except when comparing against zero.  */
              if (i == 0)
-               cmp_const = 0;
+               {
+                 cmp_const = 0;
+                 cmp_code = EQ;
+               }
              else if (neg_inc)
-               cmp_const = unroll_number - i;
+               {
+                 cmp_const = unroll_number - i;
+                 cmp_code = GE;
+               }
              else
-               cmp_const = i;
+               {
+                 cmp_const = i;
+                 cmp_code = LE;
+               }
 
              emit_cmp_insn (diff, GEN_INT (abs_inc * cmp_const),
-                            EQ, NULL_RTX, mode, 0, 0);
+                            cmp_code, NULL_RTX, mode, 0, 0);
 
              if (i == 0)
                emit_jump_insn (gen_beq (labels[i]));
@@ -865,13 +979,20 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
          if (abs_inc != 1)
            {
              int cmp_const;
+             enum rtx_code cmp_code;
 
              if (neg_inc)
-               cmp_const = abs_inc - 1;
+               {
+                 cmp_const = abs_inc - 1;
+                 cmp_code = LE;
+               }
              else
-               cmp_const = abs_inc * (unroll_number - 1) + 1;
+               {
+                 cmp_const = abs_inc * (unroll_number - 1) + 1;
+                 cmp_code = GE;
+               }
 
-             emit_cmp_insn (diff, GEN_INT (cmp_const), EQ, NULL_RTX,
+             emit_cmp_insn (diff, GEN_INT (cmp_const), cmp_code, NULL_RTX,
                             mode, 0, 0);
 
              if (neg_inc)
@@ -923,6 +1044,10 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
                if (local_label[j])
                  map->label_map[j] = gen_label_rtx ();
 
+             for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; j++)
+               if (local_regno[j])
+                 map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
+
              /* The last copy needs the compare/branch insns at the end,
                 so reset copy_end here if the loop ends with a conditional
                 branch.  */
@@ -1032,6 +1157,10 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 #endif
     }
 
+  /* Use our current register alignment and pointer flags.  */
+  map->regno_pointer_flag = regno_pointer_flag;
+  map->regno_pointer_align = 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
      the compare/jump instruction at the end of the loop to refer to the new
@@ -1060,6 +1189,10 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
        if (local_label[j])
          map->label_map[j] = gen_label_rtx ();
 
+      for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; j++)
+       if (local_regno[j])
+         map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
+
       /* If loop starts with a branch to the test, then fix it so that
         it points to the test of the first unrolled copy of the loop.  */
       if (i == 0 && loop_start != copy_start)
@@ -1242,7 +1375,7 @@ precondition_loop_p (initial_value, final_value, increment, loop_start,
   /* Fail if loop_iteration_var is not live before loop_start, since we need
      to test its value in the preconditioning code.  */
 
-  if (uid_luid[regno_first_uid[REGNO (loop_iteration_var)]]
+  if (uid_luid[REGNO_FIRST_UID (REGNO (loop_iteration_var))]
       > INSN_LUID (loop_start))
     {
       if (loop_dump_stream)
@@ -1335,10 +1468,13 @@ calculate_giv_inc (pattern, src_insn, regno)
         one of the LO_SUM rtx.  */
       if (GET_CODE (increment) == LO_SUM)
        increment = XEXP (increment, 1);
-      else if (GET_CODE (increment) == IOR)
+      else if (GET_CODE (increment) == IOR
+              || GET_CODE (increment) == ASHIFT)
        {
-         /* The rs6000 port loads some constants with IOR.  */
+         /* The rs6000 port loads some constants with IOR.
+            The alpha port loads some constants with ASHIFT.  */
          rtx second_part = XEXP (increment, 1);
+         enum rtx_code code = GET_CODE (increment);
 
          src_insn = PREV_INSN (src_insn);
          increment = SET_SRC (PATTERN (src_insn));
@@ -1349,7 +1485,10 @@ calculate_giv_inc (pattern, src_insn, regno)
              || GET_CODE (increment) != CONST_INT)
            abort ();
 
-         increment = GEN_INT (INTVAL (increment) | INTVAL (second_part));
+         if (code == IOR)
+           increment = GEN_INT (INTVAL (increment) | INTVAL (second_part));
+         else
+           increment = GEN_INT (INTVAL (increment) << INTVAL (second_part));
        }
 
       if (GET_CODE (increment) != CONST_INT)
@@ -1519,10 +1658,15 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
              for (tv = bl->giv; tv; tv = tv->next_iv)
                if (tv->giv_type == DEST_ADDR && tv->same == v)
                  {
-                   int this_giv_inc = INTVAL (giv_inc);
+                   int this_giv_inc;
+
+                   /* If this DEST_ADDR giv was not split, then ignore it.  */
+                   if (*tv->location != tv->dest_reg)
+                     continue;
 
                    /* Scale this_giv_inc if the multiplicative factors of
                       the two givs are different.  */
+                   this_giv_inc = INTVAL (giv_inc);
                    if (tv->mult_val != v->mult_val)
                      this_giv_inc = (this_giv_inc / INTVAL (v->mult_val)
                                      * INTVAL (tv->mult_val));
@@ -1545,10 +1689,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                          dest_reg = XEXP (tv->dest_reg, 0);
                        
                        /* Check for shared address givs, and avoid
-                          incrementing the shared psuedo reg more than
+                          incrementing the shared pseudo reg more than
                           once.  */
-                       if (! (tv != v && tv->insn == v->insn
-                              && tv->new_reg == v->new_reg))
+                       if (! tv->same_insn)
                          {
                            /* tv->dest_reg may actually be a (PLUS (REG)
                               (CONST)) here, so we must call plus_constant
@@ -1706,7 +1849,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
 
             If the previous insn set CC0, substitute constants on it as
             well.  */
-         if (sets_cc0_p (copy) != 0)
+         if (sets_cc0_p (PATTERN (copy)) != 0)
            cc0_insn = copy;
          else
            {
@@ -1758,8 +1901,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                {
                  rtx jmp;
                  rtx lab = gen_label_rtx ();
-                 /* Can't do it by reversing the jump (probably becasue we
-                    couln't reverse the conditions), so emit a new
+                 /* Can't do it by reversing the jump (probably because we
+                    couldn't reverse the conditions), so emit a new
                     jump_insn after COPY, and redirect the jump around
                     that.  */
                  jmp = emit_jump_insn_after (gen_jump (exit_label), copy);
@@ -1810,8 +1953,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                  /* An unrecognizable jump insn, probably the entry jump
                     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) = map->label_map[CODE_LABEL_NUMBER
-                                                    (JUMP_LABEL (insn))];
+                 JUMP_LABEL (copy)
+                   = map->label_map[CODE_LABEL_NUMBER (JUMP_LABEL (insn))];
                }
          
              /* If this is a non-local jump, then must increase the label
@@ -1868,8 +2011,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
 
          /* 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);
+         CALL_INSN_FUNCTION_USAGE (copy)
+           = copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn), map);
 
 #ifdef HAVE_cc0
          if (cc0_insn)
@@ -1985,7 +2128,7 @@ emit_unrolled_add (dest_reg, src_reg, increment)
    In practice, this is not a problem, because this function is seldom called,
    and uses a negligible amount of CPU time on average.  */
 
-static int
+int
 back_branch_in_range_p (insn, loop_start, loop_end)
      rtx insn;
      rtx loop_start, loop_end;
@@ -2137,14 +2280,16 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
                 "Loop unrolling: No reg_iv_type entry for iteration var.\n");
       return;
     }
-  /* Reject iteration variables larger than the host long size, since they
+
+  /* Reject iteration variables larger than the host wide int size, since they
      could result in a number of iterations greater than the range of our
-     `unsigned long' variable loop_n_iterations.  */
-  else if (GET_MODE_BITSIZE (GET_MODE (iteration_var)) > HOST_BITS_PER_LONG)
+     `unsigned HOST_WIDE_INT' variable loop_n_iterations.  */
+  else if ((GET_MODE_BITSIZE (GET_MODE (iteration_var))
+           > HOST_BITS_PER_WIDE_INT))
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
-                "Loop unrolling: Iteration var rejected because mode larger than host long.\n");
+                "Loop unrolling: Iteration var rejected because mode too large.\n");
       return;
     }
   else if (GET_MODE_CLASS (GET_MODE (iteration_var)) != MODE_INT)
@@ -2311,18 +2456,18 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
         it is unsafe to split the biv since it may not have the proper
         value on loop exit.  */
 
-      /* loop_number_exit_labels is non-zero if the loop has an exit other than
+      /* loop_number_exit_count is non-zero if the loop has an exit other than
         a fall through at the end.  */
 
       biv_splittable = 1;
       biv_final_value = 0;
       if (unroll_type != UNROLL_COMPLETELY
-         && (loop_number_exit_labels[uid_loop_num[INSN_UID (loop_start)]]
+         && (loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]]
              || unroll_type == UNROLL_NAIVE)
-         && (uid_luid[regno_last_uid[bl->regno]] >= INSN_LUID (loop_end)
+         && (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]]
+             || (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)))
@@ -2351,12 +2496,13 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
            {
              /* If the initial value of the biv is itself (i.e. it is too
                 complicated for strength_reduce to compute), or is a hard
-                register, then we must create a new pseudo reg to hold the
-                initial value of the biv.  */
+                register, or it isn't invariant, then we must create a new
+                pseudo reg to hold the initial value of the biv.  */
 
              if (GET_CODE (bl->initial_value) == REG
                  && (REGNO (bl->initial_value) == bl->regno
-                     || REGNO (bl->initial_value) < FIRST_PSEUDO_REGISTER))
+                     || REGNO (bl->initial_value) < FIRST_PSEUDO_REGISTER
+                     || ! invariant_p (bl->initial_value)))
                {
                  rtx tem = gen_reg_rtx (bl->biv->mode);
                  
@@ -2404,7 +2550,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_labels[uid_loop_num[INSN_UID (loop_start)]])
+         if (! loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]])
            emit_insn_before (gen_move_insn (bl->biv->src_reg,
                                             biv_final_value),
                              end_insert_before);
@@ -2435,6 +2581,33 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
   return result;
 }
 
+/* Return 1 if the first and last unrolled copy of the address giv V is valid
+   for the instruction that is using it.  Do not make any changes to that
+   instruction.  */
+
+static int
+verify_addresses (v, giv_inc, unroll_number)
+     struct induction *v;
+     rtx giv_inc;
+     int unroll_number;
+{
+  int ret = 1;
+  rtx orig_addr = *v->location;
+  rtx last_addr = plus_constant (v->dest_reg,
+                                INTVAL (giv_inc) * (unroll_number - 1));
+
+  /* First check to see if either address would fail.  */
+  if (! validate_change (v->insn, v->location, v->dest_reg, 0)
+      || ! validate_change (v->insn, v->location, last_addr, 0))
+    ret = 0;
+
+  /* Now put things back the way they were before.  This will always
+   succeed.  */
+  validate_change (v->insn, v->location, orig_addr, 0);
+
+  return ret;
+}
+
 /* For every giv based on the biv BL, check to determine whether it is
    splittable.  This is a subroutine to find_splittable_regs ().
 
@@ -2449,11 +2622,19 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
      rtx increment;
      int unroll_number;
 {
-  struct induction *v;
+  struct induction *v, *v2;
   rtx final_value;
   rtx tem;
   int result = 0;
 
+  /* Scan the list of givs, and set the same_insn field when there are
+     multiple identical givs in the same insn.  */
+  for (v = bl->giv; v; v = v->next_iv)
+    for (v2 = v->next_iv; v2; v2 = v2->next_iv)
+      if (v->insn == v2->insn && rtx_equal_p (v->new_reg, v2->new_reg)
+         && ! v2->same_insn)
+       v2->same_insn = v;
+
   for (v = bl->giv; v; v = v->next_iv)
     {
       rtx giv_inc, value;
@@ -2492,18 +2673,18 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
 
       final_value = 0;
       if (unroll_type != UNROLL_COMPLETELY
-         && (loop_number_exit_labels[uid_loop_num[INSN_UID (loop_start)]]
+         && (loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]]
              || unroll_type == UNROLL_NAIVE)
          && v->giv_type != DEST_ADDR
-         && ((regno_first_uid[REGNO (v->dest_reg)] != INSN_UID (v->insn)
+         && ((REGNO_FIRST_UID (REGNO (v->dest_reg)) != INSN_UID (v->insn)
               /* Check for the case where the pseudo is set by a shift/add
                  sequence, in which case the first insn setting the pseudo
                  is the first insn of the shift/add sequence.  */
               && (! (tem = find_reg_note (v->insn, REG_RETVAL, NULL_RTX))
-                  || (regno_first_uid[REGNO (v->dest_reg)]
+                  || (REGNO_FIRST_UID (REGNO (v->dest_reg))
                       != 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)]]
+             || (uid_luid[REGNO_LAST_UID (REGNO (v->dest_reg))]
                  >= INSN_LUID (loop_end)))
          && ! (final_value = v->final_value))
        continue;
@@ -2585,7 +2766,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
            {
              /* If value is not a constant, register, or register plus
                 constant, then compute its value into a register before
-                loop start.  This prevents illegal rtx sharing, and should
+                loop start.  This prevents invalid rtx sharing, and should
                 generate better code.  We can use bl->initial_value here
                 instead of splittable_regs[bl->regno] because this code
                 is going before the loop start.  */
@@ -2623,20 +2804,19 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                 following cse pass.  */
              
              /* As a special case, if we have multiple identical address givs
-                within a single instruction, then we do use a single psuedo
+                within a single instruction, then we do use a single pseudo
                 reg for both.  This is necessary in case one is a match_dup
                 of the other.  */
 
              v->const_adjust = 0;
 
-             if (v->same && v->same->insn == v->insn
-                 && v->new_reg == v->same->new_reg)
+             if (v->same_insn)
                {
-                 v->dest_reg = v->same->dest_reg;
+                 v->dest_reg = v->same_insn->dest_reg;
                  if (loop_dump_stream)
                    fprintf (loop_dump_stream,
-                            "Sharing address givs with reg %d\n",
-                            REGNO (v->dest_reg));
+                            "Sharing address givs in insn %d\n",
+                            INSN_UID (v->insn));
                }
              else if (unroll_type != UNROLL_COMPLETELY)
                {
@@ -2659,11 +2839,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                         Try to validate both the first and the last
                         address resulting from loop unrolling, if
                         one fails, then can't do const elim here.  */
-                     if (memory_address_p (v->mem_mode, v->dest_reg)
-                         && memory_address_p (v->mem_mode,
-                                      plus_constant (v->dest_reg,
-                                                     INTVAL (giv_inc)
-                                                     * (unroll_number - 1))))
+                     if (verify_addresses (v, giv_inc, unroll_number))
                        {
                          /* Save the negative of the eliminated const, so
                             that we can calculate the dest_reg's increment
@@ -2684,17 +2860,14 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                  
                  /* 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.  */
+                    unrolled copy of the address is not a valid address
+                    for the instruction that uses it.  */
                  if (v->dest_reg == tem
-                     && (! memory_address_p (v->mem_mode, v->dest_reg)
-                         || ! memory_address_p (v->mem_mode,
-                                plus_constant (v->dest_reg,
-                                               INTVAL (giv_inc)
-                                               * (unroll_number -1)))))
+                     && ! verify_addresses (v, giv_inc, unroll_number))
                    {
                      if (loop_dump_stream)
                        fprintf (loop_dump_stream,
-                                "Illegal address for giv at insn %d\n",
+                                "Invalid address for giv at insn %d\n",
                                 INSN_UID (v->insn));
                      continue;
                    }
@@ -2727,7 +2900,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
 
                      if (loop_dump_stream)
                        fprintf (loop_dump_stream,
-                                "Illegal init insn, rewritten.\n");
+                                "Invalid init insn, rewritten.\n");
                    }
                }
              else
@@ -2735,16 +2908,12 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                  v->dest_reg = value;
                  
                  /* Check the resulting address for validity, and fail
-                    if the resulting address would be illegal.  */
-                 if (! memory_address_p (v->mem_mode, v->dest_reg)
-                     || ! memory_address_p (v->mem_mode,
-                                    plus_constant (v->dest_reg,
-                                                   INTVAL (giv_inc) *
-                                                   (unroll_number -1))))
+                    if the resulting address would be invalid.  */
+                 if (! verify_addresses (v, giv_inc, unroll_number))
                    {
                      if (loop_dump_stream)
                        fprintf (loop_dump_stream,
-                                "Illegal address for giv at insn %d\n",
+                                "Invalid address for giv at insn %d\n",
                                 INSN_UID (v->insn));
                      continue;
                    }
@@ -2844,13 +3013,26 @@ reg_dead_after_loop (reg, loop_start, loop_end)
   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))
+    label_count++;
+
+  if (label_count != loop_number_exit_count[this_loop_num])
+    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
      list to it.  */
   label = gen_rtx (LABEL_REF, VOIDmode, loop_end);
-  LABEL_NEXTREF (label)
-    = loop_number_exit_labels[uid_loop_num[INSN_UID (loop_start)]];
+  LABEL_NEXTREF (label) = loop_number_exit_labels[this_loop_num];
 
   for ( ; label; label = LABEL_NEXTREF (label))
     {
@@ -2879,7 +3061,7 @@ reg_dead_after_loop (reg, loop_start, loop_end)
              if (GET_CODE (PATTERN (insn)) == RETURN)
                break;
              else if (! simplejump_p (insn)
-                      /* Prevent infinite loop following infinite loops. */
+                      /* Prevent infinite loop following infinite loops.  */
                       || jump_count++ > 20)
                return 0;
              else
@@ -2929,7 +3111,7 @@ final_biv_value (bl, loop_start, loop_end)
      value of the biv must be invariant.  */
 
   if (loop_n_iterations != 0
-      && ! loop_number_exit_labels[uid_loop_num[INSN_UID (loop_start)]]
+      && ! loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]]
       && invariant_p (bl->initial_value))
     {
       increment = biv_total_increment (bl, loop_start, loop_end);
@@ -3007,7 +3189,7 @@ final_giv_value (v, loop_start, loop_end)
      to be known.  */
 
   if (loop_n_iterations != 0
-      && ! loop_number_exit_labels[uid_loop_num[INSN_UID (loop_start)]])
+      && ! loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]])
     {
       /* ?? 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
@@ -3155,28 +3337,6 @@ loop_iterations (loop_start, loop_end)
     /* iteration_info already printed a message.  */
     return 0;
 
-  if (increment == 0)
-    {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
-                "Loop unrolling: Increment value can't be calculated.\n");
-      return 0;
-    }
-  if (GET_CODE (increment) != CONST_INT)
-    {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
-                "Loop unrolling: Increment value not constant.\n");
-      return 0;
-    }
-  if (GET_CODE (initial_value) != CONST_INT)
-    {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
-                "Loop unrolling: Initial value not constant.\n");
-      return 0;
-    }
-
   /* If the comparison value is an invariant register, then try to find
      its value from the insns before the start of the loop.  */
 
@@ -3224,8 +3384,30 @@ loop_iterations (loop_start, loop_end)
   loop_initial_value = initial_value;
   loop_increment = increment;
   loop_final_value = final_value;
+  loop_comparison_code = comparison_code;
 
-  if (final_value == 0)
+  if (increment == 0)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Loop unrolling: Increment value can't be calculated.\n");
+      return 0;
+    }
+  else if (GET_CODE (increment) != CONST_INT)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Loop unrolling: Increment value not constant.\n");
+      return 0;
+    }
+  else if (GET_CODE (initial_value) != CONST_INT)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Loop unrolling: Initial value not constant.\n");
+      return 0;
+    }
+  else if (final_value == 0)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -3331,7 +3513,7 @@ loop_iterations (loop_start, loop_end)
   return tempu / i + ((tempu % i) != 0);
 }
 
-/* Replace uses of split bivs with their split psuedo register.  This is
+/* Replace uses of split bivs with their split pseudo register.  This is
    for original instructions which remain after loop unrolling without
    copying.  */
 
@@ -3383,3 +3565,65 @@ remap_split_bivs (x)
     }
   return x;
 }
+
+/* If FIRST_UID is a set of REGNO, and FIRST_UID dominates LAST_UID (e.g.
+   FIST_UID is always executed if LAST_UID is), then return 1.  Otherwise
+   return 0.  COPY_START is where we can start looking for the insns
+   FIRST_UID and LAST_UID.  COPY_END is where we stop looking for these
+   insns.
+
+   If there is no JUMP_INSN between LOOP_START and FIRST_UID, then FIRST_UID
+   must dominate LAST_UID.
+
+   If there is a CODE_LABEL between FIRST_UID and LAST_UID, then FIRST_UID
+   may not dominate LAST_UID.
+
+   If there is no CODE_LABEL between FIRST_UID and LAST_UID, then FIRST_UID
+   must dominate LAST_UID.  */
+
+int
+set_dominates_use (regno, first_uid, last_uid, copy_start, copy_end)
+     int regno;
+     int first_uid;
+     int last_uid;
+     rtx copy_start;
+     rtx copy_end;
+{
+  int passed_jump = 0;
+  rtx p = NEXT_INSN (copy_start);
+
+  while (INSN_UID (p) != first_uid)
+    {
+      if (GET_CODE (p) == JUMP_INSN)
+       passed_jump= 1;
+      /* Could not find FIRST_UID.  */
+      if (p == copy_end)
+       return 0;
+      p = NEXT_INSN (p);
+    }
+
+  /* Verify that FIRST_UID is an insn that entirely sets REGNO.  */
+  if (GET_RTX_CLASS (GET_CODE (p)) != 'i'
+      || ! dead_or_set_regno_p (p, regno))
+    return 0;
+
+  /* FIRST_UID is always executed.  */
+  if (passed_jump == 0)
+    return 1;
+
+  while (INSN_UID (p) != last_uid)
+    {
+      /* If we see a CODE_LABEL between FIRST_UID and LAST_UID, then we
+        can not be sure that FIRST_UID dominates LAST_UID.  */
+      if (GET_CODE (p) == CODE_LABEL)
+       return 0;
+      /* Could not find LAST_UID, but we reached the end of the loop, so
+        it must be safe.  */
+      else if (p == copy_end)
+       return 1;
+      p = NEXT_INSN (p);
+    }
+
+  /* FIRST_UID is always executed if LAST_UID is executed.  */
+  return 1;
+}