OSDN Git Service

* ChangeLog: Follow spelling conventions.
[pf3gnuchains/gcc-fork.git] / gcc / unroll.c
index 1c66b1f..61d63d8 100644 (file)
@@ -1,24 +1,24 @@
 /* Try to unroll loops, and split induction variables.
-   Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000
+   Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
    Contributed by James E. Wilson, Cygnus Support/UC Berkeley.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 /* Try to unroll a loop, and split induction variables.
 
@@ -131,6 +131,24 @@ Boston, MA 02111-1307, USA.  */
    moving the insn back into the loop, or perhaps replicate the insn before
    the loop, one copy for each time the loop is unrolled.  */
 
+#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"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "predict.h"
+#include "params.h"
+
 /* The prime factors looked for when trying to unroll a loop by some
    number which is modulo the total number of iterations.  Just checking
    for these 4 prime factors will find at least one factor for 75% of
@@ -140,7 +158,7 @@ Boston, MA 02111-1307, USA.  */
 
 #define NUM_FACTORS 4
 
-struct _factor { int factor, count; }
+static struct _factor { const int factor; int count; }
 factors[NUM_FACTORS] = { {2, 0}, {3, 0}, {5, 0}, {7, 0}};
 
 /* Describes the different types of loop unrolling performed.  */
@@ -152,29 +170,6 @@ enum unroll_types
   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"
-#include "hard-reg-set.h"
-#include "basic-block.h"
-
-/* This controls which loops are unrolled, and by how much we unroll
-   them.  */
-
-#ifndef MAX_UNROLLED_INSNS
-#define MAX_UNROLLED_INSNS 100
-#endif
-
 /* Indexed by register number, if non-zero, then it contains a pointer
    to a struct induction for a DEST_REG giv which has been combined with
    one of more address givs.  This is needed because whenever such a DEST_REG
@@ -201,18 +196,17 @@ static int *splittable_regs_updates;
 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 final_reg_note_copy PARAMS ((rtx *, struct inline_remap *));
 static void copy_loop_body PARAMS ((struct loop *, rtx, rtx,
                                    struct inline_remap *, rtx, int,
                                    enum unroll_types, rtx, rtx, rtx, rtx));
 static int find_splittable_regs PARAMS ((const struct loop *,
-                                        enum unroll_types, rtx, int));
+                                        enum unroll_types, 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 ((struct loop *, rtx));
 static rtx find_common_reg_term PARAMS ((rtx, rtx));
 static rtx subtract_reg_term PARAMS ((rtx, rtx));
@@ -222,19 +216,16 @@ static rtx ujump_to_loop_cont PARAMS ((rtx, rtx));
 /* Try to unroll one loop and split induction variables in the loop.
 
    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.
+   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, insn_count, end_insert_before, strength_reduce_p)
+unroll_loop (loop, insn_count, strength_reduce_p)
      struct loop *loop;
      int insn_count;
-     rtx end_insert_before;
      int strength_reduce_p;
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
@@ -276,53 +267,6 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
       return;
     }
 
-  /* When emitting debugger info, we can't unroll loops with unequal numbers
-     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 (1 /* write_symbols != NO_DEBUG */)
-    {
-      int block_begins = 0;
-      int block_ends = 0;
-
-      for (insn = loop_start; insn != loop_end; insn = NEXT_INSN (insn))
-       {
-         if (GET_CODE (insn) == NOTE)
-           {
-             if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
-               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;
-               }
-           }
-       }
-
-      if (block_begins != block_ends)
-       {
-         if (loop_dump_stream)
-           fprintf (loop_dump_stream,
-                    "Unrolling failure: Unbalanced block notes.\n");
-         return;
-       }
-    }
-
   /* Determine type of unroll to perform.  Depends on the number of iterations
      and the size of the loop.  */
 
@@ -357,7 +301,7 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
 
       rtx ujump = ujump_to_loop_cont (loop->start, loop->cont);
       if (ujump)
-       delete_insn (ujump);
+       delete_related_insns (ujump);
 
       /* If number of iterations is exactly 1, then eliminate the compare and
         branch at the end of the loop since they will never be taken.
@@ -369,38 +313,38 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
       if (GET_CODE (last_loop_insn) == BARRIER)
        {
          /* Delete the jump insn.  This will delete the barrier also.  */
-         delete_insn (PREV_INSN (last_loop_insn));
+         delete_related_insns (PREV_INSN (last_loop_insn));
        }
       else if (GET_CODE (last_loop_insn) == JUMP_INSN)
        {
 #ifdef HAVE_cc0
          rtx prev = PREV_INSN (last_loop_insn);
 #endif
-         delete_insn (last_loop_insn);
+         delete_related_insns (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);
+         if (only_sets_cc0_p (prev))
+           delete_related_insns (prev);
 #endif
        }
 
       /* Remove the loop notes since this is no longer a loop.  */
       if (loop->vtop)
-       delete_insn (loop->vtop);
+       delete_related_insns (loop->vtop);
       if (loop->cont)
-       delete_insn (loop->cont);
+       delete_related_insns (loop->cont);
       if (loop_start)
-       delete_insn (loop_start);
+       delete_related_insns (loop_start);
       if (loop_end)
-       delete_insn (loop_end);
+       delete_related_insns (loop_end);
 
       return;
     }
   else if (loop_info->n_iterations > 0
           /* Avoid overflow in the next expression.  */
-          && loop_info->n_iterations < MAX_UNROLLED_INSNS
-          && loop_info->n_iterations * insn_count < MAX_UNROLLED_INSNS)
+          && loop_info->n_iterations < (unsigned) MAX_UNROLLED_INSNS
+          && loop_info->n_iterations * insn_count < (unsigned) MAX_UNROLLED_INSNS)
     {
       unroll_number = loop_info->n_iterations;
       unroll_type = UNROLL_COMPLETELY;
@@ -430,7 +374,7 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
       for (i = 3; i >= 0; i--)
        while (factors[i].count--)
          {
-           if (temp * factors[i].factor < MAX_UNROLLED_INSNS)
+           if (temp * factors[i].factor < (unsigned) MAX_UNROLLED_INSNS)
              {
                unroll_number *= factors[i].factor;
                temp *= factors[i].factor;
@@ -729,8 +673,7 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
 
   if (max_labelno > 0)
     {
-      map->label_map = (rtx *) xmalloc (max_labelno * sizeof (rtx));
-
+      map->label_map = (rtx *) xcalloc (max_labelno, sizeof (rtx));
       local_label = (char *) xcalloc (max_labelno, sizeof (char));
     }
 
@@ -768,7 +711,7 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
                }
            }
        }
-      else if ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)))
+      if ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)))
        set_label_in_map (map, CODE_LABEL_NUMBER (XEXP (note, 0)),
                          XEXP (note, 0));
     }
@@ -900,9 +843,12 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
                               &initial_value, &final_value, &increment,
                               &mode))
        {
-         register rtx diff;
+         rtx diff;
          rtx *labels;
          int abs_inc, neg_inc;
+         enum rtx_code cc = loop_info->comparison_code;
+         int less_p     = (cc == LE  || cc == LEU || cc == LT  || cc == LTU);
+         int unsigned_p = (cc == LEU || cc == GEU || cc == LTU || cc == GTU);
 
          map->reg_map = (rtx *) xmalloc (maxregnum * sizeof (rtx));
 
@@ -929,23 +875,50 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
 
          start_sequence ();
 
+         /* Final value may have form of (PLUS val1 const1_rtx).  We need
+            to convert it into general operand, so compute the real value.  */
+
+         if (GET_CODE (final_value) == PLUS)
+           {
+             final_value = expand_simple_binop (mode, PLUS,
+                                                copy_rtx (XEXP (final_value, 0)),
+                                                copy_rtx (XEXP (final_value, 1)),
+                                                NULL_RTX, 0, OPTAB_LIB_WIDEN);
+           }
+         if (!nonmemory_operand (final_value, VOIDmode))
+           final_value = force_reg (mode, copy_rtx (final_value));
+
          /* Calculate the difference between the final and initial values.
             Final value may be a (plus (reg x) (const_int 1)) rtx.
             Let the following cse pass simplify this if initial value is
             a constant.
 
             We must copy the final and initial values here to avoid
-            improperly shared rtl.  */
-
-         diff = expand_binop (mode, sub_optab, copy_rtx (final_value),
-                              copy_rtx (initial_value), NULL_RTX, 0,
-                              OPTAB_LIB_WIDEN);
+            improperly shared rtl.
+
+            We have to deal with for (i = 0; --i < 6;) type loops.
+            For such loops the real final value is the first time the
+            loop variable overflows, so the diff we calculate is the
+            distance from the overflow value.  This is 0 or ~0 for
+            unsigned loops depending on the direction, or INT_MAX,
+            INT_MAX+1 for signed loops.  We really do not need the
+            exact value, since we are only interested in the diff
+            modulo the increment, and the increment is a power of 2,
+            so we can pretend that the overflow value is 0/~0.  */
+
+         if (cc == NE || less_p != neg_inc)
+           diff = expand_simple_binop (mode, MINUS, final_value,
+                                       copy_rtx (initial_value), NULL_RTX, 0,
+                                       OPTAB_LIB_WIDEN);
+         else
+           diff = expand_simple_unop (mode, neg_inc ? NOT : NEG,
+                                      copy_rtx (initial_value), NULL_RTX, 0);
 
          /* Now calculate (diff % (unroll * abs (increment))) by using an
             and instruction.  */
-         diff = expand_binop (GET_MODE (diff), and_optab, diff,
-                              GEN_INT (unroll_number * abs_inc - 1),
-                              NULL_RTX, 0, OPTAB_LIB_WIDEN);
+         diff = expand_simple_binop (GET_MODE (diff), AND, diff,
+                                     GEN_INT (unroll_number * abs_inc - 1),
+                                     NULL_RTX, 0, OPTAB_LIB_WIDEN);
 
          /* Now emit a sequence of branches to jump to the proper precond
             loop entry point.  */
@@ -960,11 +933,19 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
             case.  This check does not apply if the loop has a NE
             comparison at the end.  */
 
-         if (loop_info->comparison_code != NE)
+         if (cc != NE)
            {
-             emit_cmp_and_jump_insns (initial_value, final_value,
-                                      neg_inc ? LE : GE,
-                                      NULL_RTX, mode, 0, 0, labels[1]);
+             rtx incremented_initval;
+             incremented_initval = expand_simple_binop (mode, PLUS,
+                                                        initial_value,
+                                                        increment,
+                                                        NULL_RTX, 0,
+                                                        OPTAB_LIB_WIDEN);
+             emit_cmp_and_jump_insns (incremented_initval, final_value,
+                                      less_p ? GE : LE, NULL_RTX,
+                                      mode, unsigned_p, labels[1]);
+             predict_insn_def (get_last_insn (), PRED_LOOP_CONDITION,
+                               TAKEN);
              JUMP_LABEL (get_last_insn ()) = labels[1];
              LABEL_NUSES (labels[1])++;
            }
@@ -1006,10 +987,11 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
                }
 
              emit_cmp_and_jump_insns (diff, GEN_INT (abs_inc * cmp_const),
-                                      cmp_code, NULL_RTX, mode, 0, 0,
-                                      labels[i]);
+                                      cmp_code, NULL_RTX, mode, 0, labels[i]);
              JUMP_LABEL (get_last_insn ()) = labels[i];
              LABEL_NUSES (labels[i])++;
+             predict_insn (get_last_insn (), PRED_LOOP_PRECONDITIONING,
+                           REG_BR_PROB_BASE / (unroll_number - i));
            }
 
          /* If the increment is greater than one, then we need another branch,
@@ -1038,14 +1020,14 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
                }
 
              emit_cmp_and_jump_insns (diff, GEN_INT (cmp_const), cmp_code,
-                                      NULL_RTX, mode, 0, 0, labels[0]);
+                                      NULL_RTX, mode, 0, labels[0]);
              JUMP_LABEL (get_last_insn ()) = labels[0];
              LABEL_NUSES (labels[0])++;
            }
 
-         sequence = gen_sequence ();
+         sequence = get_insns ();
          end_sequence ();
-         emit_insn_before (sequence, loop_start);
+         loop_insn_hoist (loop, sequence);
 
          /* Only the last copy of the loop body here needs the exit
             test, so set copy_end to exclude the compare/branch here,
@@ -1152,6 +1134,9 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
   /* Keep track of the unroll factor for the loop.  */
   loop_info->unroll_number = unroll_number;
 
+  /* And whether the loop has been preconditioned.  */
+  loop_info->preconditioned = loop_preconditioned;
+
   /* For each biv and giv, determine whether it can be safely split into
      a different variable for each unrolled copy of the loop body.
      We precalculate and save this info here, since computing it is
@@ -1163,8 +1148,7 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
   if (splitting_not_safe)
     temp = 0;
   else
-    temp = find_splittable_regs (loop, unroll_type,
-                                end_insert_before, unroll_number);
+    temp = find_splittable_regs (loop, unroll_type, 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
@@ -1184,7 +1168,7 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
   /* Search the list of bivs and givs to find ones which need to be remapped
      when split, and set their reg_map entry appropriately.  */
 
-  for (bl = ivs->loop_iv_list; bl; bl = bl->next)
+  for (bl = ivs->list; bl; bl = bl->next)
     {
       if (REGNO (bl->biv->src_reg) != bl->regno)
        map->reg_map[bl->regno] = bl->biv->src_reg;
@@ -1291,16 +1275,16 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
          && ! (GET_CODE (insn) == CODE_LABEL && LABEL_NAME (insn))
          && ! (GET_CODE (insn) == NOTE
                && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL))
-       insn = delete_insn (insn);
+       insn = delete_related_insns (insn);
       else
        insn = NEXT_INSN (insn);
     }
 
   /* Can now delete the 'safety' label emitted to protect us from runaway
-     delete_insn calls.  */
+     delete_related_insns calls.  */
   if (INSN_DELETED_P (safety_label))
     abort ();
-  delete_insn (safety_label);
+  delete_related_insns (safety_label);
 
   /* If exit_label exists, emit it after the loop.  Doing the emit here
      forces it to have a higher INSN_UID than any insn in the unrolled loop.
@@ -1315,13 +1299,13 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
     {
       /* Remove the loop notes since this is no longer a loop.  */
       if (loop->vtop)
-       delete_insn (loop->vtop);
+       delete_related_insns (loop->vtop);
       if (loop->cont)
-       delete_insn (loop->cont);
+       delete_related_insns (loop->cont);
       if (loop_start)
-       delete_insn (loop_start);
+       delete_related_insns (loop_start);
       if (loop_end)
-       delete_insn (loop_end);
+       delete_related_insns (loop_end);
     }
 
   if (map->const_equiv_varray)
@@ -1369,9 +1353,18 @@ precondition_loop_p (loop, initial_value, final_value, increment, mode)
 
   if (loop_info->n_iterations > 0)
     {
-      *initial_value = const0_rtx;
-      *increment = const1_rtx;
-      *final_value = GEN_INT (loop_info->n_iterations);
+      if (INTVAL (loop_info->increment) > 0)
+       {
+         *initial_value = const0_rtx;
+         *increment = const1_rtx;
+         *final_value = GEN_INT (loop_info->n_iterations);
+       }
+      else
+       {
+         *initial_value = GEN_INT (loop_info->n_iterations);
+         *increment = constm1_rtx;
+         *final_value = const0_rtx;
+       }
       *mode = word_mode;
 
       if (loop_dump_stream)
@@ -1385,7 +1378,14 @@ precondition_loop_p (loop, initial_value, final_value, increment, mode)
       return 1;
     }
 
-  if (loop_info->initial_value == 0)
+  if (loop_info->iteration_var == 0)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Preconditioning: Could not find iteration variable.\n");
+      return 0;
+    }
+  else if (loop_info->initial_value == 0)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -1549,13 +1549,13 @@ calculate_giv_inc (pattern, src_insn, regno)
       /* SR sometimes computes the new giv value in a temp, then copies it
         to the new_reg.  */
       src_insn = PREV_INSN (src_insn);
-      pattern = PATTERN (src_insn);
+      pattern = single_set (src_insn);
       if (GET_CODE (SET_SRC (pattern)) != PLUS)
        abort ();
 
       /* The last insn emitted is not needed, so delete it to avoid confusing
         the second cse pass.  This insn sets the giv unnecessarily.  */
-      delete_insn (get_last_insn ());
+      delete_related_insns (get_last_insn ());
     }
 
   /* Verify that we have a constant as the second operand of the plus.  */
@@ -1564,8 +1564,7 @@ calculate_giv_inc (pattern, src_insn, regno)
     {
       /* SR sometimes puts the constant in a register, especially if it is
         too big to be an add immed operand.  */
-      src_insn = PREV_INSN (src_insn);
-      increment = SET_SRC (PATTERN (src_insn));
+      increment = find_last_value (increment, &src_insn, NULL_RTX, 0);
 
       /* SR may have used LO_SUM to compute the constant if it is too large
         for a load immed operand.  In this case, the constant is in operand
@@ -1591,10 +1590,10 @@ calculate_giv_inc (pattern, src_insn, regno)
          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));
+         increment = find_last_value (XEXP (increment, 0),
+                                      &src_insn, NULL_RTX, 0);
          /* Don't need the last insn anymore.  */
-         delete_insn (get_last_insn ());
+         delete_related_insns (get_last_insn ());
 
          if (GET_CODE (second_part) != CONST_INT
              || GET_CODE (increment) != CONST_INT)
@@ -1613,7 +1612,7 @@ calculate_giv_inc (pattern, src_insn, regno)
 
       /* The insn loading the constant into a register is no longer needed,
         so delete it.  */
-      delete_insn (get_last_insn ());
+      delete_related_insns (get_last_insn ());
     }
 
   if (increment_total)
@@ -1635,9 +1634,9 @@ calculate_giv_inc (pattern, src_insn, regno)
          tries++;
 
          src_insn = PREV_INSN (src_insn);
-         pattern = PATTERN (src_insn);
+         pattern = single_set (src_insn);
 
-         delete_insn (get_last_insn ());
+         delete_related_insns (get_last_insn ());
 
          goto retry;
        }
@@ -1663,13 +1662,13 @@ initial_reg_note_copy (notes, map)
     return 0;
 
   copy = rtx_alloc (GET_CODE (notes));
-  PUT_MODE (copy, GET_MODE (notes));
+  PUT_REG_NOTE_KIND (copy, REG_NOTE_KIND (notes));
 
   if (GET_CODE (notes) == EXPR_LIST)
     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);
+    XEXP (copy, 0) = copy_rtx (XEXP (notes, 0));
   else
     abort ();
 
@@ -1681,15 +1680,43 @@ initial_reg_note_copy (notes, map)
 /* Fixup insn references in copied REG_NOTES.  */
 
 static void
-final_reg_note_copy (notes, map)
-     rtx notes;
+final_reg_note_copy (notesp, map)
+     rtx *notesp;
      struct inline_remap *map;
 {
-  rtx note;
+  while (*notesp)
+    {
+      rtx note = *notesp;
+
+      if (GET_CODE (note) == INSN_LIST)
+       {
+         /* Sometimes, we have a REG_WAS_0 note that points to a
+            deleted instruction.  In that case, we can just delete the
+            note.  */
+         if (REG_NOTE_KIND (note) == REG_WAS_0)
+           {
+             *notesp = XEXP (note, 1);
+             continue;
+           }
+         else
+           {
+             rtx insn = map->insn_map[INSN_UID (XEXP (note, 0))];
+
+             /* If we failed to remap the note, something is awry.
+                Allow REG_LABEL as it may reference label outside
+                the unrolled loop.  */
+             if (!insn)
+               {
+                 if (REG_NOTE_KIND (note) != REG_LABEL)
+                   abort ();
+               }
+             else
+               XEXP (note, 0) = insn;
+           }
+       }
 
-  for (note = notes; note; note = XEXP (note, 1))
-    if (GET_CODE (note) == INSN_LIST)
-      XEXP (note, 0) = map->insn_map[INSN_UID (XEXP (note, 0))];
+      notesp = &XEXP (note, 1);
+    }
 }
 
 /* Copy each instruction in the loop, substituting from map as appropriate.
@@ -1733,12 +1760,6 @@ copy_loop_body (loop, 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
     {
@@ -1912,7 +1933,7 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
                     for the biv was stored in the biv's first struct
                     induction entry by find_splittable_regs.  */
 
-                 if (regno < max_reg_before_loop
+                 if (regno < ivs->n_regs
                      && REG_IV_TYPE (ivs, regno) == BASIC_INDUCT)
                    {
                      giv_src_reg = REG_IV_CLASS (ivs, regno)->biv->src_reg;
@@ -1974,6 +1995,7 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
              copy = emit_insn (pattern);
            }
          REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map);
+         INSN_SCOPE (copy) = INSN_SCOPE (insn);
 
 #ifdef HAVE_cc0
          /* If this insn is setting CC0, it may need to look at
@@ -2020,15 +2042,18 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
          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);
+         INSN_SCOPE (copy) = INSN_SCOPE (insn);
 
-         if (JUMP_LABEL (insn) == start_label && insn == copy_end
-             && ! last_iteration)
+         if (JUMP_LABEL (insn))
            {
-             /* Update JUMP_LABEL make invert_jump work correctly.  */
              JUMP_LABEL (copy) = get_label_from_map (map,
                                                      CODE_LABEL_NUMBER
                                                      (JUMP_LABEL (insn)));
              LABEL_NUSES (JUMP_LABEL (copy))++;
+           }
+         if (JUMP_LABEL (insn) == start_label && insn == copy_end
+             && ! last_iteration)
+           {
 
              /* This is a branch to the beginning of the loop; this is the
                 last insn being copied; and this is not the last iteration.
@@ -2045,6 +2070,8 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
                     jump_insn after COPY, and redirect the jump around
                     that.  */
                  jmp = emit_jump_insn_after (gen_jump (exit_label), copy);
+                 JUMP_LABEL (jmp) = exit_label;
+                 LABEL_NUSES (exit_label)++;
                  jmp = emit_barrier_after (jmp);
                  emit_label_after (lab, jmp);
                  LABEL_NUSES (lab) = 0;
@@ -2117,21 +2144,14 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
            {
 #ifdef HAVE_cc0
              /* If the previous insn set cc0 for us, delete it.  */
-             if (sets_cc0_p (PREV_INSN (copy)))
-               delete_insn (PREV_INSN (copy));
+             if (only_sets_cc0_p (PREV_INSN (copy)))
+               delete_related_insns (PREV_INSN (copy));
 #endif
 
              /* If this is now a no-op, delete it.  */
              if (map->last_pc_value == pc_rtx)
                {
-                 /* Don't let delete_insn delete the label referenced here,
-                    because we might possibly need it later for some other
-                    instruction in the loop.  */
-                 if (JUMP_LABEL (copy))
-                   LABEL_NUSES (JUMP_LABEL (copy))++;
                  delete_insn (copy);
-                 if (JUMP_LABEL (copy))
-                   LABEL_NUSES (JUMP_LABEL (copy))--;
                  copy = 0;
                }
              else
@@ -2146,6 +2166,8 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
          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);
+         INSN_SCOPE (copy) = INSN_SCOPE (insn);
+         SIBLING_CALL_P (copy) = SIBLING_CALL_P (insn);
 
          /* Because the USAGE information potentially contains objects other
             than hard registers, we need to copy it.  */
@@ -2216,7 +2238,7 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
       if ((GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
           || GET_CODE (insn) == CALL_INSN)
          && map->insn_map[INSN_UID (insn)])
-       final_reg_note_copy (REG_NOTES (map->insn_map[INSN_UID (insn)]), map);
+       final_reg_note_copy (&REG_NOTES (map->insn_map[INSN_UID (insn)]), map);
     }
   while (insn != copy_end);
 
@@ -2236,15 +2258,15 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
        {
          /* 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.  */
+            Although COPY_NOTES_FROM will be at most one or two (for cc0)
+            instructions before the last insn in the loop, COPY_NOTES_FROM
+            can be a NOTE_INSN_LOOP_CONT note if there is no VTOP note,
+            as in a do .. while loop.  */
          if (GET_CODE (insn) == NOTE
              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
-             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP)
+             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP
+             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_CONT)
            emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
        }
     }
@@ -2252,9 +2274,9 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
   if (final_label && LABEL_NUSES (final_label) > 0)
     emit_label (final_label);
 
-  tem = gen_sequence ();
+  tem = get_insns ();
   end_sequence ();
-  emit_insn_before (tem, insert_before);
+  loop_insn_emit_before (loop, 0, insert_before, tem);
 }
 \f
 /* Emit an insn, using the expand_binop to ensure that a valid insn is
@@ -2267,8 +2289,8 @@ emit_unrolled_add (dest_reg, src_reg, increment)
 {
   rtx result;
 
-  result = expand_binop (GET_MODE (dest_reg), add_optab, src_reg, increment,
-                        dest_reg, 0, OPTAB_LIB_WIDEN);
+  result = expand_simple_binop (GET_MODE (dest_reg), PLUS, src_reg, increment,
+                               dest_reg, 0, OPTAB_LIB_WIDEN);
 
   if (dest_reg != result)
     emit_move_insn (dest_reg, result);
@@ -2381,7 +2403,7 @@ fold_rtx_mult_add (mult1, mult2, add1, mode)
 
 rtx
 biv_total_increment (bl)
-     struct iv_class *bl;
+     const struct iv_class *bl;
 {
   struct induction *v;
   rtx result;
@@ -2397,7 +2419,8 @@ biv_total_increment (bl)
   for (v = bl->biv; v; v = v->next_iv)
     {
       if (v->always_computable && v->mult_val == const1_rtx
-         && ! v->maybe_multiple)
+         && ! v->maybe_multiple
+         && SCALAR_INT_MODE_P (v->mode))
        result = fold_rtx_mult_add (result, const1_rtx, v->add_val, v->mode);
       else
        return 0;
@@ -2431,10 +2454,9 @@ biv_total_increment (bl)
    times, since multiplies by small integers (1,2,3,4) are very cheap.  */
 
 static int
-find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
+find_splittable_regs (loop, unroll_type, unroll_number)
      const struct loop *loop;
      enum unroll_types unroll_type;
-     rtx end_insert_before;
      int unroll_number;
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
@@ -2444,10 +2466,8 @@ find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
   rtx biv_final_value;
   int biv_splittable;
   int result = 0;
-  rtx loop_start = loop->start;
-  rtx loop_end = loop->end;
 
-  for (bl = ivs->loop_iv_list; bl; bl = bl->next)
+  for (bl = ivs->list; bl; bl = bl->next)
     {
       /* Biv_total_increment must return a constant value,
         otherwise we can not calculate the split values.  */
@@ -2469,7 +2489,7 @@ find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
       biv_final_value = 0;
       if (unroll_type != UNROLL_COMPLETELY
          && (loop->exit_count || unroll_type == UNROLL_NAIVE)
-         && (REGNO_LAST_LUID (bl->regno) >= INSN_LUID (loop_end)
+         && (REGNO_LAST_LUID (bl->regno) >= INSN_LUID (loop->end)
              || ! bl->init_insn
              || INSN_UID (bl->init_insn) >= max_uid_for_loop
              || (REGNO_FIRST_LUID (bl->regno)
@@ -2512,8 +2532,8 @@ find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
                  rtx tem = gen_reg_rtx (bl->biv->mode);
 
                  record_base_value (REGNO (tem), bl->biv->add_val, 0);
-                 emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
-                                   loop_start);
+                 loop_insn_hoist (loop,
+                                  gen_move_insn (tem, bl->biv->src_reg));
 
                  if (loop_dump_stream)
                    fprintf (loop_dump_stream,
@@ -2558,9 +2578,8 @@ find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
             how the loop exits.  Otherwise emit the insn after the loop,
             since this is slightly more efficient.  */
          if (! loop->exit_count)
-           emit_insn_before (gen_move_insn (bl->biv->src_reg,
-                                            biv_final_value),
-                             end_insert_before);
+           loop_insn_sink (loop, gen_move_insn (bl->biv->src_reg,
+                                                biv_final_value));
          else
            {
              /* Create a new register to hold the value of the biv, and then
@@ -2571,11 +2590,9 @@ find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
              rtx tem = gen_reg_rtx (bl->biv->mode);
              record_base_value (REGNO (tem), bl->biv->add_val, 0);
 
-             emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
-                               loop_start);
-             emit_insn_before (gen_move_insn (bl->biv->src_reg,
-                                              biv_final_value),
-                               loop_start);
+             loop_insn_hoist (loop, gen_move_insn (tem, bl->biv->src_reg));
+             loop_insn_hoist (loop, gen_move_insn (bl->biv->src_reg,
+                                                   biv_final_value));
 
              if (loop_dump_stream)
                fprintf (loop_dump_stream, "Biv %d mapped to %d for split.\n",
@@ -2590,35 +2607,6 @@ find_splittable_regs (loop, unroll_type, end_insert_before, unroll_number)
   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.   Handle the fact
-     that we have may have a match_dup.  */
-  if (! validate_replace_rtx (*v->location, v->dest_reg, v->insn)
-      || ! validate_replace_rtx (*v->location, last_addr, v->insn))
-    ret = 0;
-
-  /* Now put things back the way they were before.  This should always
-   succeed.  */
-  if (! validate_replace_rtx (*v->location, orig_addr, v->insn))
-    abort ();
-
-  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 ().
 
@@ -2630,7 +2618,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
      struct iv_class *bl;
      enum unroll_types unroll_type;
      rtx increment;
-     int unroll_number;
+     int unroll_number ATTRIBUTE_UNUSED;
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct induction *v, *v2;
@@ -2717,9 +2705,8 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
             to its final value before loop start to ensure that this insn
             will always be executed, no matter how we exit.  */
          tem = gen_reg_rtx (v->mode);
-         emit_insn_before (gen_move_insn (tem, v->dest_reg), loop_start);
-         emit_insn_before (gen_move_insn (v->dest_reg, final_value),
-                           loop_start);
+         loop_insn_hoist (loop, gen_move_insn (tem, v->dest_reg));
+         loop_insn_hoist (loop, gen_move_insn (v->dest_reg, final_value));
 
          if (loop_dump_stream)
            fprintf (loop_dump_stream, "Giv %d mapped to %d for split.\n",
@@ -2752,8 +2739,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
              rtx tem = gen_reg_rtx (bl->biv->mode);
 
              record_base_value (REGNO (tem), bl->biv->add_val, 0);
-             emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
-                               loop->start);
+             loop_insn_hoist (loop, gen_move_insn (tem, bl->biv->src_reg));
              biv_initial_value = tem;
            }
          biv_initial_value = extend_value_for_giv (v, biv_initial_value);
@@ -2795,213 +2781,15 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
                {
                  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);
+                 loop_iv_add_mult_hoist (loop, bl->initial_value, v->mult_val,
+                                         v->add_val, tem);
                  value = tem;
                }
 
              splittable_regs[REGNO (v->new_reg)] = value;
            }
          else
-           {
-             /* Splitting address givs is useful since it will often allow us
-                to eliminate some increment insns for the base giv as
-                unnecessary.  */
-
-             /* If the addr giv is combined with a dest_reg giv, then all
-                references to that dest reg will be remapped, which is NOT
-                what we want for split addr regs. We always create a new
-                register for the split addr giv, just to be safe.  */
-
-             /* If we have multiple identical address givs within a
-                single instruction, then 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_insn)
-               {
-                 v->dest_reg = v->same_insn->dest_reg;
-                 if (loop_dump_stream)
-                   fprintf (loop_dump_stream,
-                            "Sharing address givs in insn %d\n",
-                            INSN_UID (v->insn));
-               }
-             /* If multiple address GIVs have been combined with the
-                same dest_reg GIV, do not create a new register for
-                each.  */
-             else if (unroll_type != UNROLL_COMPLETELY
-                      && v->giv_type == DEST_ADDR
-                      && v->same && v->same->giv_type == DEST_ADDR
-                      && v->same->unrolled
-                      /* combine_givs_p may return true for some cases
-                         where the add and mult values are not equal.
-                         To share a register here, the values must be
-                         equal.  */
-                      && rtx_equal_p (v->same->mult_val, v->mult_val)
-                      && rtx_equal_p (v->same->add_val, v->add_val)
-                      /* If the memory references have different modes,
-                         then the address may not be valid and we must
-                         not share registers.  */
-                      && verify_addresses (v, giv_inc, unroll_number))
-               {
-                 v->dest_reg = v->same->dest_reg;
-                 v->shared = 1;
-               }
-             else if (unroll_type != UNROLL_COMPLETELY)
-               {
-                 /* If not completely unrolling the loop, then create a new
-                    register to hold the split value of the DEST_ADDR giv.
-                    Emit insn to initialize its value before loop start.  */
-
-                 rtx tem = gen_reg_rtx (v->mode);
-                 struct induction *same = v->same;
-                 rtx new_reg = v->new_reg;
-                 record_base_value (REGNO (tem), v->add_val, 0);
-
-                 /* If the address giv has a constant in its new_reg value,
-                    then this constant can be pulled out and put in value,
-                    instead of being part of the initialization code.  */
-
-                 if (GET_CODE (new_reg) == PLUS
-                     && GET_CODE (XEXP (new_reg, 1)) == CONST_INT)
-                   {
-                     v->dest_reg
-                       = plus_constant (tem, INTVAL (XEXP (new_reg, 1)));
-
-                     /* Only succeed if this will give valid addresses.
-                        Try to validate both the first and the last
-                        address resulting from loop unrolling, if
-                        one fails, then can't do const elim here.  */
-                     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
-                            value later.  */
-                         v->const_adjust = -INTVAL (XEXP (new_reg, 1));
-
-                         new_reg = XEXP (new_reg, 0);
-                         if (loop_dump_stream)
-                           fprintf (loop_dump_stream,
-                                    "Eliminating constant from giv %d\n",
-                                    REGNO (tem));
-                       }
-                     else
-                       v->dest_reg = tem;
-                   }
-                 else
-                   v->dest_reg = tem;
-
-                 /* If the address hasn't been checked for validity yet, do so
-                    now, and fail completely if either the first or the last
-                    unrolled copy of the address is not a valid address
-                    for the instruction that uses it.  */
-                 if (v->dest_reg == tem
-                     && ! verify_addresses (v, giv_inc, unroll_number))
-                   {
-                     for (v2 = v->next_iv; v2; v2 = v2->next_iv)
-                       if (v2->same_insn == v)
-                         v2->same_insn = 0;
-
-                     if (loop_dump_stream)
-                       fprintf (loop_dump_stream,
-                                "Invalid address for giv at insn %d\n",
-                                INSN_UID (v->insn));
-                     continue;
-                   }
-
-                 v->new_reg = new_reg;
-                 v->same = same;
-
-                 /* We set this after the address check, to guarantee that
-                    the register will be initialized.  */
-                 v->unrolled = 1;
-
-                 /* To initialize the new register, just move the value of
-                    new_reg into it.  This is not guaranteed to give a valid
-                    instruction on machines with complex addressing modes.
-                    If we can't recognize it, then delete it and emit insns
-                    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)
-                   {
-                     rtx sequence, ret;
-
-                     /* We can't use bl->initial_value to compute the initial
-                        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));
-
-                     start_sequence ();
-                     ret = force_operand (v->new_reg, tem);
-                     if (ret != tem)
-                       emit_move_insn (tem, ret);
-                     sequence = gen_sequence ();
-                     end_sequence ();
-                     emit_insn_before (sequence, loop->start);
-
-                     if (loop_dump_stream)
-                       fprintf (loop_dump_stream,
-                                "Invalid init insn, rewritten.\n");
-                   }
-               }
-             else
-               {
-                 v->dest_reg = value;
-
-                 /* Check the resulting address for validity, and fail
-                    if the resulting address would be invalid.  */
-                 if (! verify_addresses (v, giv_inc, unroll_number))
-                   {
-                     for (v2 = v->next_iv; v2; v2 = v2->next_iv)
-                       if (v2->same_insn == v)
-                         v2->same_insn = 0;
-
-                     if (loop_dump_stream)
-                       fprintf (loop_dump_stream,
-                                "Invalid address for giv at insn %d\n",
-                                INSN_UID (v->insn));
-                     continue;
-                   }
-               }
-
-             /* Store the value of dest_reg into the insn.  This sharing
-                will not be a problem as this insn will always be copied
-                later.  */
-
-             *v->location = v->dest_reg;
-
-             /* If this address giv is combined with a dest reg giv, then
-                save the base giv's induction pointer so that we will be
-                able to handle this address giv properly.  The base giv
-                itself does not have to be splittable.  */
-
-             if (v->same && v->same->giv_type == DEST_REG)
-               addr_combined_regs[REGNO (v->same->new_reg)] = v->same;
-
-             if (GET_CODE (v->new_reg) == REG)
-               {
-                 /* This giv maybe hasn't been combined with any others.
-                    Make sure that it's giv is marked as splittable here.  */
-
-                 splittable_regs[REGNO (v->new_reg)] = value;
-
-                 /* Make it appear to depend upon itself, so that the
-                    giv will be properly split in the main loop above.  */
-                 if (! v->same)
-                   {
-                     v->same = v;
-                     addr_combined_regs[REGNO (v->new_reg)] = v;
-                   }
-               }
-
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream, "DEST_ADDR giv being split.\n");
-           }
+           continue;
        }
       else
        {
@@ -3140,7 +2928,6 @@ final_biv_value (loop, bl)
      const struct loop *loop;
      struct iv_class *bl;
 {
-  rtx loop_end = loop->end;
   unsigned HOST_WIDE_INT n_iterations = LOOP_INFO (loop)->n_iterations;
   rtx increment, tem;
 
@@ -3182,11 +2969,8 @@ final_biv_value (loop, bl)
 
          tem = gen_reg_rtx (bl->biv->mode);
          record_base_value (REGNO (tem), bl->biv->add_val, 0);
-         /* Make sure loop_end is not the last insn.  */
-         if (NEXT_INSN (loop_end) == 0)
-           emit_note_after (NOTE_INSN_DELETED, loop_end);
-         emit_iv_add_mult (increment, GEN_INT (n_iterations),
-                           bl->initial_value, tem, NEXT_INSN (loop_end));
+         loop_iv_add_mult_sink (loop, increment, GEN_INT (n_iterations),
+                                bl->initial_value, tem);
 
          if (loop_dump_stream)
            fprintf (loop_dump_stream,
@@ -3222,7 +3006,7 @@ final_giv_value (loop, v)
   struct iv_class *bl;
   rtx insn;
   rtx increment, tem;
-  rtx insert_before, seq;
+  rtx seq;
   rtx loop_end = loop->end;
   unsigned HOST_WIDE_INT n_iterations = LOOP_INFO (loop)->n_iterations;
 
@@ -3243,7 +3027,8 @@ final_giv_value (loop, v)
 
   /* Try to calculate the final value as a function of the biv it depends
      upon.  The only exit from the loop must be the fall through at the bottom
-     (otherwise it may not have its final value when the loop exits).  */
+     and the insn that sets the giv must be executed on every iteration
+     (otherwise the giv may not have its final value when the loop exits).  */
 
   /* ??? Can calculate the final giv value by subtracting off the
      extra biv increments times the giv's mult_val.  The loop must have
@@ -3251,7 +3036,8 @@ final_giv_value (loop, v)
      to be known.  */
 
   if (n_iterations != 0
-      && ! loop->exit_count)
+      && ! loop->exit_count
+      && v->always_executed)
     {
       /* ?? 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
@@ -3279,15 +3065,13 @@ final_giv_value (loop, v)
             We must search from the insn that sets the giv to the end
             of the loop to calculate this value.  */
 
-         insert_before = NEXT_INSN (loop_end);
-
          /* Put the final biv value in tem.  */
          tem = gen_reg_rtx (v->mode);
          record_base_value (REGNO (tem), bl->biv->add_val, 0);
-         emit_iv_add_mult (extend_value_for_giv (v, increment),
-                           GEN_INT (n_iterations),
-                           extend_value_for_giv (v, bl->initial_value),
-                           tem, insert_before);
+         loop_iv_add_mult_sink (loop, extend_value_for_giv (v, increment),
+                                GEN_INT (n_iterations),
+                                extend_value_for_giv (v, bl->initial_value),
+                                tem);
 
          /* Subtract off extra increments as we find them.  */
          for (insn = NEXT_INSN (v->insn); insn != loop_end;
@@ -3299,17 +3083,17 @@ final_giv_value (loop, v)
                if (biv->insn == insn)
                  {
                    start_sequence ();
-                   tem = expand_binop (GET_MODE (tem), sub_optab, tem,
-                                       biv->add_val, NULL_RTX, 0,
-                                       OPTAB_LIB_WIDEN);
-                   seq = gen_sequence ();
+                   tem = expand_simple_binop (GET_MODE (tem), MINUS, tem,
+                                              biv->add_val, NULL_RTX, 0,
+                                              OPTAB_LIB_WIDEN);
+                   seq = get_insns ();
                    end_sequence ();
-                   emit_insn_before (seq, insert_before);
+                   loop_insn_sink (loop, seq);
                  }
            }
 
          /* Now calculate the giv's final value.  */
-         emit_iv_add_mult (tem, v->mult_val, v->add_val, tem, insert_before);
+         loop_iv_add_mult_sink (loop, tem, v->mult_val, v->add_val, tem);
 
          if (loop_dump_stream)
            fprintf (loop_dump_stream,
@@ -3338,7 +3122,7 @@ final_giv_value (loop, v)
   return 0;
 }
 
-/* Look back before LOOP->START for then insn that sets REG and return
+/* Look back before LOOP->START for the insn that sets REG and return
    the equivalent constant if there is a REG_EQUAL note otherwise just
    the SET_SRC of REG.  */
 
@@ -3464,7 +3248,8 @@ loop_iterations (loop)
   rtx comparison, comparison_value;
   rtx iteration_var, initial_value, increment, final_value;
   enum rtx_code comparison_code;
-  HOST_WIDE_INT abs_inc;
+  HOST_WIDE_INT inc;
+  unsigned HOST_WIDE_INT abs_inc;
   unsigned HOST_WIDE_INT abs_diff;
   int off_by_one;
   int increment_dir;
@@ -3488,7 +3273,7 @@ loop_iterations (loop)
      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_nonnote_insn (loop->end);
 
   /* ??? We should probably try harder to find the jump insn
      at the end of the loop.  The following code assumes that
@@ -3511,6 +3296,44 @@ loop_iterations (loop)
       return 0;
     }
 
+  /* If there are multiple conditionalized loop exit tests, they may jump
+     back to differing CODE_LABELs.  */
+  if (loop->top && loop->cont)
+    {
+      rtx temp = PREV_INSN (last_loop_insn);
+
+      do
+       {
+         if (GET_CODE (temp) == JUMP_INSN)
+           {
+             /* There are some kinds of jumps we can't deal with easily.  */
+             if (JUMP_LABEL (temp) == 0)
+               {
+                 if (loop_dump_stream)
+                   fprintf
+                     (loop_dump_stream,
+                      "Loop iterations: Jump insn has null JUMP_LABEL.\n");
+                 return 0;
+               }
+
+             if (/* Previous unrolling may have generated new insns not
+                    covered by the uid_luid array.  */
+                 INSN_UID (JUMP_LABEL (temp)) < max_uid_for_loop
+                 /* Check if we jump back into the loop body.  */
+                 && INSN_LUID (JUMP_LABEL (temp)) > INSN_LUID (loop->top)
+                 && INSN_LUID (JUMP_LABEL (temp)) < INSN_LUID (loop->cont))
+               {
+                 if (loop_dump_stream)
+                   fprintf
+                     (loop_dump_stream,
+                      "Loop iterations: Loop has multiple back edges.\n");
+                 return 0;
+               }
+           }
+       }
+      while ((temp = PREV_INSN (temp)) != loop->cont);
+    }
+
   /* Find the iteration variable.  If the last insn is a conditional
      branch, and the insn before tests a register value, make that the
      iteration variable.  */
@@ -3545,7 +3368,7 @@ loop_iterations (loop)
      will propagate a new pseudo into the old iteration register but
      this will be marked by having the REG_USERVAR_P bit set.  */
 
-  if ((unsigned) REGNO (iteration_var) >= ivs->reg_iv_type->num_elements
+  if ((unsigned) REGNO (iteration_var) >= ivs->n_regs
       && ! REG_USERVAR_P (iteration_var))
     abort ();
 
@@ -3563,7 +3386,7 @@ loop_iterations (loop)
 
   /* 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) >= ivs->reg_iv_type->num_elements)
+  if ((unsigned) REGNO (iteration_var) >= ivs->n_regs)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -3591,15 +3414,19 @@ loop_iterations (loop)
     }
   else if (REG_IV_TYPE (ivs, 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)
+      if (REGNO (iteration_var) >= ivs->n_regs)
        abort ();
 
       /* Grab initial value, only useful if it is a constant.  */
       bl = REG_IV_CLASS (ivs, REGNO (iteration_var));
       initial_value = bl->initial_value;
+      if (!bl->biv->always_executed || bl->biv->maybe_multiple)
+       {
+         if (loop_dump_stream)
+           fprintf (loop_dump_stream,
+                    "Loop iterations: Basic induction var not set once in each iteration.\n");
+         return 0;
+       }
 
       increment = biv_total_increment (bl);
     }
@@ -3609,9 +3436,17 @@ loop_iterations (loop)
       struct induction *v = REG_IV_INFO (ivs, REGNO (iteration_var));
       rtx biv_initial_value;
 
-      if (REGNO (v->src_reg) >= max_reg_before_loop)
+      if (REGNO (v->src_reg) >= ivs->n_regs)
        abort ();
 
+      if (!v->always_executed || v->maybe_multiple)
+       {
+         if (loop_dump_stream)
+           fprintf (loop_dump_stream,
+                    "Loop iterations: General induction var not set once in each iteration.\n");
+         return 0;
+       }
+
       bl = REG_IV_CLASS (ivs, REGNO (v->src_reg));
 
       /* Increment value is mult_val times the increment value of the biv.  */
@@ -3624,7 +3459,7 @@ loop_iterations (loop)
          increment = fold_rtx_mult_add (v->mult_val,
                                         extend_value_for_giv (v, increment),
                                         const0_rtx, v->mode);
-         /* The caller assumes that one full increment has occured at the
+         /* The caller assumes that one full increment has occurred 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) .
@@ -3633,9 +3468,19 @@ loop_iterations (loop)
          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);
+               {
+                 if (REG_P (biv_inc->add_val))
+                   {
+                     if (loop_dump_stream)
+                       fprintf (loop_dump_stream,
+                                "Loop iterations: Basic induction var add_val is REG %d.\n",
+                                REGNO (biv_inc->add_val));
+                       return 0;
+                   }
+
+                 offset -= INTVAL (biv_inc->add_val);
+               }
            }
-         offset *= INTVAL (v->mult_val);
        }
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -3855,7 +3700,7 @@ loop_iterations (loop)
            {
              fprintf (loop_dump_stream,
                       "Loop iterations: Increment value not constant ");
-             print_rtl (loop_dump_stream, increment);
+             print_simple_rtl (loop_dump_stream, increment);
              fprintf (loop_dump_stream, ".\n");
            }
          return 0;
@@ -3869,28 +3714,59 @@ loop_iterations (loop)
        {
          fprintf (loop_dump_stream,
                   "Loop iterations: Initial value not constant ");
-         print_rtl (loop_dump_stream, initial_value);
+         print_simple_rtl (loop_dump_stream, initial_value);
          fprintf (loop_dump_stream, ".\n");
        }
       return 0;
     }
-  else if (comparison_code == EQ)
-    {
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream, "Loop iterations: EQ comparison loop.\n");
-      return 0;
-    }
   else if (GET_CODE (final_value) != CONST_INT)
     {
       if (loop_dump_stream)
        {
          fprintf (loop_dump_stream,
                   "Loop iterations: Final value not constant ");
-         print_rtl (loop_dump_stream, final_value);
+         print_simple_rtl (loop_dump_stream, final_value);
          fprintf (loop_dump_stream, ".\n");
        }
       return 0;
     }
+  else if (comparison_code == EQ)
+    {
+      rtx inc_once;
+
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream, "Loop iterations: EQ comparison loop.\n");
+
+      inc_once = gen_int_mode (INTVAL (initial_value) + INTVAL (increment),
+                              GET_MODE (iteration_var));
+
+      if (inc_once == final_value)
+       {
+         /* The iterator value once through the loop is equal to the
+            comparision value.  Either we have an infinite loop, or
+            we'll loop twice.  */
+         if (increment == const0_rtx)
+           return 0;
+         loop_info->n_iterations = 2;
+       }
+      else
+       loop_info->n_iterations = 1;
+
+      if (GET_CODE (loop_info->initial_value) == CONST_INT)
+       loop_info->final_value
+         = gen_int_mode ((INTVAL (loop_info->initial_value)
+                          + loop_info->n_iterations * INTVAL (increment)),
+                         GET_MODE (iteration_var));
+      else
+       loop_info->final_value
+         = plus_constant (loop_info->initial_value,
+                          loop_info->n_iterations * INTVAL (increment));
+      loop_info->final_equiv_value
+       = gen_int_mode ((INTVAL (initial_value)
+                        + loop_info->n_iterations * INTVAL (increment)),
+                       GET_MODE (iteration_var));
+      return loop_info->n_iterations;
+    }
 
   /* Final_larger is 1 if final larger, 0 if they are equal, otherwise -1.  */
   if (unsigned_p)
@@ -3952,17 +3828,28 @@ loop_iterations (loop)
      so correct for that.  Note that abs_diff and n_iterations are
      unsigned, because they can be as large as 2^n - 1.  */
 
-  abs_inc = INTVAL (increment);
-  if (abs_inc > 0)
-    abs_diff = INTVAL (final_value) - INTVAL (initial_value);
-  else if (abs_inc < 0)
+  inc = INTVAL (increment);
+  if (inc > 0)
+    {
+      abs_diff = INTVAL (final_value) - INTVAL (initial_value);
+      abs_inc = inc;
+    }
+  else if (inc < 0)
     {
       abs_diff = INTVAL (initial_value) - INTVAL (final_value);
-      abs_inc = -abs_inc;
+      abs_inc = -inc;
     }
   else
     abort ();
 
+  /* Given that iteration_var is going to iterate over its own mode,
+     not HOST_WIDE_INT, disregard higher bits that might have come
+     into the picture due to sign extension of initial and final
+     values.  */
+  abs_diff &= ((unsigned HOST_WIDE_INT) 1
+              << (GET_MODE_BITSIZE (GET_MODE (iteration_var)) - 1)
+              << 1) - 1;
+
   /* For NE tests, make sure that the iteration variable won't miss
      the final value.  If abs_diff mod abs_incr is not zero, then the
      iteration variable will overflow before the loop exits, and we
@@ -3987,9 +3874,9 @@ remap_split_bivs (loop, x)
      rtx x;
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
-  register enum rtx_code code;
-  register int i;
-  register const char *fmt;
+  enum rtx_code code;
+  int i;
+  const char *fmt;
 
   if (x == 0)
     return x;
@@ -4012,7 +3899,7 @@ remap_split_bivs (loop, x)
       /* If non-reduced/final-value givs were split, then this would also
         have to remap those givs also.  */
 #endif
-      if (REGNO (x) < max_reg_before_loop
+      if (REGNO (x) < ivs->n_regs
          && REG_IV_TYPE (ivs, REGNO (x)) == BASIC_INDUCT)
        return REG_IV_CLASS (ivs, REGNO (x))->biv->src_reg;
       break;
@@ -4028,7 +3915,7 @@ remap_split_bivs (loop, x)
        XEXP (x, i) = remap_split_bivs (loop, XEXP (x, i));
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            XVECEXP (x, i, j) = remap_split_bivs (loop, XVECEXP (x, i, j));
        }