OSDN Git Service

* config/m68k/m68k-protos.h: Convert to ISO C90.
[pf3gnuchains/gcc-fork.git] / gcc / unroll.c
index 4096905..1c66b13 100644 (file)
@@ -1,5 +1,6 @@
 /* Try to unroll loops, and split induction variables.
-   Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002
+   Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
+   2002, 2003
    Free Software Foundation, Inc.
    Contributed by James E. Wilson, Cygnus Support/UC Berkeley.
 
@@ -69,7 +70,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 /* ??? Improve control of which loops get unrolled.  Could use profiling
    info to only unroll the most commonly executed loops.  Perhaps have
-   a user specifyable option to control the amount of code expansion,
+   a user specifiable option to control the amount of code expansion,
    or the percent of loops to consider for unrolling.  Etc.  */
 
 /* ??? Look at the register copies inside the loop to see if they form a
@@ -133,6 +134,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "insn-config.h"
@@ -148,6 +151,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "basic-block.h"
 #include "predict.h"
 #include "params.h"
+#include "cfgloop.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
@@ -170,7 +174,7 @@ enum unroll_types
   UNROLL_NAIVE
 };
 
-/* Indexed by register number, if non-zero, then it contains a pointer
+/* Indexed by register number, if nonzero, 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
    giv is modified, we must modify the value of all split address givs
@@ -193,25 +197,26 @@ static int *splittable_regs_updates;
 
 /* Forward declarations.  */
 
-static void init_reg_map PARAMS ((struct inline_remap *, int));
-static rtx calculate_giv_inc PARAMS ((rtx, rtx, unsigned int));
-static rtx initial_reg_note_copy PARAMS ((rtx, struct inline_remap *));
-static void final_reg_note_copy PARAMS ((rtx *, struct inline_remap *));
-static void copy_loop_body PARAMS ((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, 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 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));
-static rtx loop_find_equiv_value PARAMS ((const struct loop *, rtx));
-static rtx ujump_to_loop_cont PARAMS ((rtx, rtx));
+static rtx simplify_cmp_and_jump_insns (enum rtx_code, enum machine_mode,
+                                       rtx, rtx, rtx);
+static void init_reg_map (struct inline_remap *, int);
+static rtx calculate_giv_inc (rtx, rtx, unsigned int);
+static rtx initial_reg_note_copy (rtx, struct inline_remap *);
+static void final_reg_note_copy (rtx *, struct inline_remap *);
+static void copy_loop_body (struct loop *, rtx, rtx,
+                           struct inline_remap *, rtx, int,
+                           enum unroll_types, rtx, rtx, rtx, rtx);
+static int find_splittable_regs (const struct loop *, enum unroll_types,
+                                int);
+static int find_splittable_givs (const struct loop *, struct iv_class *,
+                                enum unroll_types, rtx, int);
+static int reg_dead_after_loop (const struct loop *, rtx);
+static rtx fold_rtx_mult_add (rtx, rtx, rtx, enum machine_mode);
+static rtx remap_split_bivs (struct loop *, rtx);
+static rtx find_common_reg_term (rtx, rtx);
+static rtx subtract_reg_term (rtx, rtx);
+static rtx loop_find_equiv_value (const struct loop *, rtx);
+static rtx ujump_to_loop_cont (rtx, rtx);
 
 /* Try to unroll one loop and split induction variables in the loop.
 
@@ -223,10 +228,7 @@ static rtx ujump_to_loop_cont PARAMS ((rtx, rtx));
    in loop.c.  */
 
 void
-unroll_loop (loop, insn_count, strength_reduce_p)
-     struct loop *loop;
-     int insn_count;
-     int strength_reduce_p;
+unroll_loop (struct loop *loop, int insn_count, int strength_reduce_p)
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_ivs *ivs = LOOP_IVS (loop);
@@ -279,12 +281,8 @@ unroll_loop (loop, insn_count, strength_reduce_p)
     loop_info->n_iterations = 0;
 
   if (loop_dump_stream && loop_info->n_iterations > 0)
-    {
-      fputs ("Loop unrolling: ", loop_dump_stream);
-      fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC,
-              loop_info->n_iterations);
-      fputs (" iterations.\n", loop_dump_stream);
-    }
+    fprintf (loop_dump_stream, "Loop unrolling: " HOST_WIDE_INT_PRINT_DEC
+            " iterations.\n", loop_info->n_iterations);
 
   /* Find and save a pointer to the last nonnote insn in the loop.  */
 
@@ -299,9 +297,11 @@ unroll_loop (loop, insn_count, strength_reduce_p)
         jump to the loop condition.  Make sure to delete the jump
         insn, otherwise the loop body will never execute.  */
 
+      /* FIXME this actually checks for a jump to the continue point, which
+        is not the same as the condition in a for loop.  As a result, this
+        optimization fails for most for loops.  We should really use flow
+        information rather than instruction pattern matching.  */
       rtx ujump = ujump_to_loop_cont (loop->start, loop->cont);
-      if (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.
@@ -313,9 +313,10 @@ unroll_loop (loop, insn_count, strength_reduce_p)
       if (GET_CODE (last_loop_insn) == BARRIER)
        {
          /* Delete the jump insn.  This will delete the barrier also.  */
-         delete_related_insns (PREV_INSN (last_loop_insn));
+         last_loop_insn = PREV_INSN (last_loop_insn);
        }
-      else if (GET_CODE (last_loop_insn) == JUMP_INSN)
+
+      if (ujump && GET_CODE (last_loop_insn) == JUMP_INSN)
        {
 #ifdef HAVE_cc0
          rtx prev = PREV_INSN (last_loop_insn);
@@ -327,24 +328,27 @@ unroll_loop (loop, insn_count, strength_reduce_p)
          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_related_insns (loop->vtop);
-      if (loop->cont)
-       delete_related_insns (loop->cont);
-      if (loop_start)
-       delete_related_insns (loop_start);
-      if (loop_end)
-       delete_related_insns (loop_end);
+         delete_related_insns (ujump);
 
-      return;
+         /* Remove the loop notes since this is no longer a loop.  */
+         if (loop->vtop)
+           delete_related_insns (loop->vtop);
+         if (loop->cont)
+           delete_related_insns (loop->cont);
+         if (loop_start)
+           delete_related_insns (loop_start);
+         if (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 < (unsigned) MAX_UNROLLED_INSNS
-          && loop_info->n_iterations * insn_count < (unsigned) MAX_UNROLLED_INSNS)
+
+  if (loop_info->n_iterations > 0
+      /* Avoid overflow in the next expression.  */
+      && 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;
@@ -667,14 +671,14 @@ unroll_loop (loop, insn_count, strength_reduce_p)
      without initializing fields within the map structure.
 
      To be safe, we use xcalloc to zero the memory.  */
-  map = (struct inline_remap *) xcalloc (1, sizeof (struct inline_remap));
+  map = xcalloc (1, sizeof (struct inline_remap));
 
   /* Allocate the label map.  */
 
   if (max_labelno > 0)
     {
-      map->label_map = (rtx *) xcalloc (max_labelno, sizeof (rtx));
-      local_label = (char *) xcalloc (max_labelno, sizeof (char));
+      map->label_map = xcalloc (max_labelno, sizeof (rtx));
+      local_label = xcalloc (max_labelno, sizeof (char));
     }
 
   /* Search the loop and mark all local labels, i.e. the ones which have to
@@ -718,7 +722,7 @@ unroll_loop (loop, insn_count, strength_reduce_p)
 
   /* Allocate space for the insn map.  */
 
-  map->insn_map = (rtx *) xmalloc (max_insnno * sizeof (rtx));
+  map->insn_map = xmalloc (max_insnno * sizeof (rtx));
 
   /* Set this to zero, to indicate that we are doing loop unrolling,
      not function inlining.  */
@@ -744,11 +748,10 @@ unroll_loop (loop, insn_count, strength_reduce_p)
      preconditioning code and find_splittable_regs will never be used
      to access the splittable_regs[] and addr_combined_regs[] arrays.  */
 
-  splittable_regs = (rtx *) xcalloc (maxregnum, sizeof (rtx));
-  splittable_regs_updates = (int *) xcalloc (maxregnum, sizeof (int));
-  addr_combined_regs
-    = (struct induction **) xcalloc (maxregnum, sizeof (struct induction *));
-  local_regno = (char *) xcalloc (maxregnum, sizeof (char));
+  splittable_regs = xcalloc (maxregnum, sizeof (rtx));
+  splittable_regs_updates = xcalloc (maxregnum, sizeof (int));
+  addr_combined_regs = xcalloc (maxregnum, sizeof (struct induction *));
+  local_regno = xcalloc (maxregnum, sizeof (char));
 
   /* Mark all local registers, i.e. the ones which are referenced only
      inside the loop.  */
@@ -783,9 +786,9 @@ unroll_loop (loop, insn_count, strength_reduce_p)
       /* We must limit the generic test to max_reg_before_loop, because only
         these pseudo registers have valid regno_first_uid info.  */
       for (r = FIRST_PSEUDO_REGISTER; r < max_reg_before_loop; ++r)
-       if (REGNO_FIRST_UID (r) > 0 && REGNO_FIRST_UID (r) <= max_uid_for_loop
+       if (REGNO_FIRST_UID (r) > 0 && REGNO_FIRST_UID (r) < max_uid_for_loop
            && REGNO_FIRST_LUID (r) >= copy_start_luid
-           && REGNO_LAST_UID (r) > 0 && REGNO_LAST_UID (r) <= max_uid_for_loop
+           && REGNO_LAST_UID (r) > 0 && REGNO_LAST_UID (r) < max_uid_for_loop
            && REGNO_LAST_LUID (r) <= copy_end_luid)
          {
            /* However, we must also check for loop-carried dependencies.
@@ -843,14 +846,14 @@ unroll_loop (loop, insn_count, strength_reduce_p)
                               &initial_value, &final_value, &increment,
                               &mode))
        {
-         rtx diff;
+         rtx diff, insn;
          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));
+         map->reg_map = xmalloc (maxregnum * sizeof (rtx));
 
          VARRAY_CONST_EQUIV_INIT (map->const_equiv_varray, maxregnum,
                                   "unroll_loop_precondition");
@@ -875,26 +878,20 @@ unroll_loop (loop, insn_count, strength_reduce_p)
 
          start_sequence ();
 
+         /* We must copy the final and initial values here to avoid
+            improperly shared rtl.  */
+         final_value = copy_rtx (final_value);
+         initial_value = copy_rtx (initial_value);
+
          /* 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);
-           }
+         final_value = force_operand (final_value, NULL_RTX);
          if (!nonmemory_operand (final_value, VOIDmode))
-           final_value = force_reg (mode, copy_rtx (final_value));
+           final_value = force_reg (mode, 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.
 
             We have to deal with for (i = 0; --i < 6;) type loops.
             For such loops the real final value is the first time the
@@ -907,23 +904,23 @@ unroll_loop (loop, insn_count, strength_reduce_p)
             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);
+           diff = simplify_gen_binary (MINUS, mode, final_value,
+                                       initial_value);
          else
-           diff = expand_simple_unop (mode, neg_inc ? NOT : NEG,
-                                      copy_rtx (initial_value), NULL_RTX, 0);
+           diff = simplify_gen_unary (neg_inc ? NOT : NEG, mode,
+                                      initial_value, mode);
+         diff = force_operand (diff, NULL_RTX);
 
          /* Now calculate (diff % (unroll * abs (increment))) by using an
             and instruction.  */
-         diff = expand_simple_binop (GET_MODE (diff), AND, diff,
-                                     GEN_INT (unroll_number * abs_inc - 1),
-                                     NULL_RTX, 0, OPTAB_LIB_WIDEN);
+         diff = simplify_gen_binary (AND, mode, diff,
+                                     GEN_INT (unroll_number*abs_inc - 1));
+         diff = force_operand (diff, NULL_RTX);
 
          /* Now emit a sequence of branches to jump to the proper precond
             loop entry point.  */
 
-         labels = (rtx *) xmalloc (sizeof (rtx) * unroll_number);
+         labels = xmalloc (sizeof (rtx) * unroll_number);
          for (i = 0; i < unroll_number; i++)
            labels[i] = gen_label_rtx ();
 
@@ -936,18 +933,22 @@ unroll_loop (loop, insn_count, strength_reduce_p)
          if (cc != NE)
            {
              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])++;
+             enum rtx_code cmp_code;
+
+             incremented_initval
+               = simplify_gen_binary (PLUS, mode, initial_value, increment);
+             incremented_initval
+               = force_operand (incremented_initval, NULL_RTX);
+
+             cmp_code = (less_p
+                         ? (unsigned_p ? GEU : GE)
+                         : (unsigned_p ? LEU : LE));
+
+             insn = simplify_cmp_and_jump_insns (cmp_code, mode,
+                                                 incremented_initval,
+                                                 final_value, labels[1]);
+             if (insn)
+               predict_insn_def (insn, PRED_LOOP_CONDITION, TAKEN);
            }
 
          /* Assuming the unroll_number is 4, and the increment is 2, then
@@ -986,12 +987,12 @@ unroll_loop (loop, insn_count, strength_reduce_p)
                  cmp_code = LE;
                }
 
-             emit_cmp_and_jump_insns (diff, GEN_INT (abs_inc * cmp_const),
-                                      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));
+             insn = simplify_cmp_and_jump_insns (cmp_code, mode, diff,
+                                                 GEN_INT (abs_inc*cmp_const),
+                                                 labels[i]);
+             if (insn)
+               predict_insn (insn, PRED_LOOP_PRECONDITIONING,
+                             REG_BR_PROB_BASE / (unroll_number - i));
            }
 
          /* If the increment is greater than one, then we need another branch,
@@ -1019,10 +1020,8 @@ unroll_loop (loop, insn_count, strength_reduce_p)
                  cmp_code = GE;
                }
 
-             emit_cmp_and_jump_insns (diff, GEN_INT (cmp_const), cmp_code,
-                                      NULL_RTX, mode, 0, labels[0]);
-             JUMP_LABEL (get_last_insn ()) = labels[0];
-             LABEL_NUSES (labels[0])++;
+             simplify_cmp_and_jump_insns (cmp_code, mode, diff,
+                                          GEN_INT (cmp_const), labels[0]);
            }
 
          sequence = get_insns ();
@@ -1054,8 +1053,8 @@ unroll_loop (loop, insn_count, strength_reduce_p)
              emit_label_after (labels[unroll_number - i],
                                PREV_INSN (loop_start));
 
-             memset ((char *) map->insn_map, 0, max_insnno * sizeof (rtx));
-             memset ((char *) &VARRAY_CONST_EQUIV (map->const_equiv_varray, 0),
+             memset (map->insn_map, 0, max_insnno * sizeof (rtx));
+             memset (&VARRAY_CONST_EQUIV (map->const_equiv_varray, 0),
                      0, (VARRAY_SIZE (map->const_equiv_varray)
                          * sizeof (struct const_equiv_data)));
              map->const_age = 0;
@@ -1121,7 +1120,7 @@ unroll_loop (loop, insn_count, strength_reduce_p)
 
   /* If reach here, and the loop type is UNROLL_NAIVE, then don't unroll
      the loop unless all loops are being unrolled.  */
-  if (unroll_type == UNROLL_NAIVE && ! flag_unroll_all_loops)
+  if (unroll_type == UNROLL_NAIVE && ! flag_old_unroll_all_loops)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -1137,6 +1136,9 @@ unroll_loop (loop, insn_count, strength_reduce_p)
   /* And whether the loop has been preconditioned.  */
   loop_info->preconditioned = loop_preconditioned;
 
+  /* Remember whether it was preconditioned for the second loop pass.  */
+  NOTE_PRECONDITIONED (loop->end) = 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
@@ -1155,7 +1157,7 @@ unroll_loop (loop, insn_count, strength_reduce_p)
      the constant maps also.  */
 
   maxregnum = max_reg_num ();
-  map->reg_map = (rtx *) xmalloc (maxregnum * sizeof (rtx));
+  map->reg_map = xmalloc (maxregnum * sizeof (rtx));
 
   init_reg_map (map, maxregnum);
 
@@ -1203,8 +1205,8 @@ unroll_loop (loop, insn_count, strength_reduce_p)
 
   for (i = 0; i < unroll_number; i++)
     {
-      memset ((char *) map->insn_map, 0, max_insnno * sizeof (rtx));
-      memset ((char *) &VARRAY_CONST_EQUIV (map->const_equiv_varray, 0), 0,
+      memset (map->insn_map, 0, max_insnno * sizeof (rtx));
+      memset (&VARRAY_CONST_EQUIV (map->const_equiv_varray, 0), 0,
              VARRAY_SIZE (map->const_equiv_varray) * sizeof (struct const_equiv_data));
       map->const_age = 0;
 
@@ -1324,6 +1326,41 @@ unroll_loop (loop, insn_count, strength_reduce_p)
     free (map->reg_map);
   free (map);
 }
+
+/* A helper function for unroll_loop.  Emit a compare and branch to
+   satisfy (CMP OP1 OP2), but pass this through the simplifier first.
+   If the branch turned out to be conditional, return it, otherwise
+   return NULL.  */
+
+static rtx
+simplify_cmp_and_jump_insns (enum rtx_code code, enum machine_mode mode,
+                            rtx op0, rtx op1, rtx label)
+{
+  rtx t, insn;
+
+  t = simplify_relational_operation (code, mode, op0, op1);
+  if (!t)
+    {
+      enum rtx_code scode = signed_condition (code);
+      emit_cmp_and_jump_insns (op0, op1, scode, NULL_RTX, mode,
+                              code != scode, label);
+      insn = get_last_insn ();
+
+      JUMP_LABEL (insn) = label;
+      LABEL_NUSES (label) += 1;
+
+      return insn;
+    }
+  else if (t == const_true_rtx)
+    {
+      insn = emit_jump_insn (gen_jump (label));
+      emit_barrier ();
+      JUMP_LABEL (insn) = label;
+      LABEL_NUSES (label) += 1;
+    }
+
+  return NULL_RTX;
+}
 \f
 /* Return true if the loop can be safely, and profitably, preconditioned
    so that the unrolled copies of the loop body don't need exit tests.
@@ -1343,10 +1380,9 @@ unroll_loop (loop, insn_count, strength_reduce_p)
    reflected in RTX_COST.  */
 
 int
-precondition_loop_p (loop, initial_value, final_value, increment, mode)
-     const struct loop *loop;
-     rtx *initial_value, *final_value, *increment;
-     enum machine_mode *mode;
+precondition_loop_p (const struct loop *loop, rtx *initial_value,
+                    rtx *final_value, rtx *increment,
+                    enum machine_mode *mode)
 {
   rtx loop_start = loop->start;
   struct loop_info *loop_info = LOOP_INFO (loop);
@@ -1368,13 +1404,10 @@ precondition_loop_p (loop, initial_value, final_value, increment, mode)
       *mode = word_mode;
 
       if (loop_dump_stream)
-       {
-         fputs ("Preconditioning: Success, number of iterations known, ",
-                loop_dump_stream);
-         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC,
-                  loop_info->n_iterations);
-         fputs (".\n", loop_dump_stream);
-       }
+       fprintf (loop_dump_stream,
+                "Preconditioning: Success, number of iterations known, "
+                HOST_WIDE_INT_PRINT_DEC ".\n",
+                loop_info->n_iterations);
       return 1;
     }
 
@@ -1506,9 +1539,7 @@ precondition_loop_p (loop, initial_value, final_value, increment, mode)
    modes.  */
 
 static void
-init_reg_map (map, maxregnum)
-     struct inline_remap *map;
-     int maxregnum;
+init_reg_map (struct inline_remap *map, int maxregnum)
 {
   int i;
 
@@ -1533,9 +1564,7 @@ init_reg_map (map, maxregnum)
    The return value is the amount that the giv is incremented by.  */
 
 static rtx
-calculate_giv_inc (pattern, src_insn, regno)
-     rtx pattern, src_insn;
-     unsigned int regno;
+calculate_giv_inc (rtx pattern, rtx src_insn, unsigned int regno)
 {
   rtx increment;
   rtx increment_total = 0;
@@ -1582,11 +1611,13 @@ calculate_giv_inc (pattern, src_insn, regno)
        }
 
       else if (GET_CODE (increment) == IOR
+              || GET_CODE (increment) == PLUS
               || GET_CODE (increment) == ASHIFT
-              || GET_CODE (increment) == PLUS)
+              || GET_CODE (increment) == LSHIFTRT)
        {
          /* The rs6000 port loads some constants with IOR.
-            The alpha port loads some constants with ASHIFT and PLUS.  */
+            The alpha port loads some constants with ASHIFT and PLUS.
+            The sparc64 port loads some constants with LSHIFTRT.  */
          rtx second_part = XEXP (increment, 1);
          enum rtx_code code = GET_CODE (increment);
 
@@ -1603,8 +1634,10 @@ calculate_giv_inc (pattern, src_insn, regno)
            increment = GEN_INT (INTVAL (increment) | INTVAL (second_part));
          else if (code == PLUS)
            increment = GEN_INT (INTVAL (increment) + INTVAL (second_part));
-         else
+         else if (code == ASHIFT)
            increment = GEN_INT (INTVAL (increment) << INTVAL (second_part));
+         else
+           increment = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (increment) >> INTVAL (second_part));
        }
 
       if (GET_CODE (increment) != CONST_INT)
@@ -1652,9 +1685,7 @@ calculate_giv_inc (pattern, src_insn, regno)
    the reg_map entries can change during copying.  */
 
 static rtx
-initial_reg_note_copy (notes, map)
-     rtx notes;
-     struct inline_remap *map;
+initial_reg_note_copy (rtx notes, struct inline_remap *map)
 {
   rtx copy;
 
@@ -1680,9 +1711,7 @@ initial_reg_note_copy (notes, map)
 /* Fixup insn references in copied REG_NOTES.  */
 
 static void
-final_reg_note_copy (notesp, map)
-     rtx *notesp;
-     struct inline_remap *map;
+final_reg_note_copy (rtx *notesp, struct inline_remap *map)
 {
   while (*notesp)
     {
@@ -1690,29 +1719,18 @@ final_reg_note_copy (notesp, map)
 
       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)
+         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)
            {
-             *notesp = XEXP (note, 1);
-             continue;
+             if (REG_NOTE_KIND (note) != REG_LABEL)
+               abort ();
            }
          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;
-           }
+           XEXP (note, 0) = insn;
        }
 
       notesp = &XEXP (note, 1);
@@ -1723,16 +1741,11 @@ final_reg_note_copy (notesp, map)
    This is very similar to a loop in expand_inline_function.  */
 
 static void
-copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
-               unroll_type, start_label, loop_end, insert_before,
-               copy_notes_from)
-     struct loop *loop;
-     rtx copy_start, copy_end;
-     struct inline_remap *map;
-     rtx exit_label;
-     int last_iteration;
-     enum unroll_types unroll_type;
-     rtx start_label, loop_end, insert_before, copy_notes_from;
+copy_loop_body (struct loop *loop, rtx copy_start, rtx copy_end,
+               struct inline_remap *map, rtx exit_label,
+               int last_iteration, enum unroll_types unroll_type,
+               rtx start_label, rtx loop_end, rtx insert_before,
+               rtx copy_notes_from)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   rtx insn, pattern;
@@ -1995,7 +2008,14 @@ 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);
+         INSN_LOCATOR (copy) = INSN_LOCATOR (insn);
+
+         /* If there is a REG_EQUAL note present whose value
+            is not loop invariant, then delete it, since it
+            may cause problems with later optimization passes.  */
+         if ((tem = find_reg_note (copy, REG_EQUAL, NULL_RTX))
+             && !loop_invariant_p (loop, XEXP (tem, 0)))
+           remove_note (copy, tem);
 
 #ifdef HAVE_cc0
          /* If this insn is setting CC0, it may need to look at
@@ -2042,7 +2062,7 @@ 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);
+         INSN_LOCATOR (copy) = INSN_LOCATOR (insn);
 
          if (JUMP_LABEL (insn))
            {
@@ -2166,8 +2186,9 @@ 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);
+         INSN_LOCATOR (copy) = INSN_LOCATOR (insn);
          SIBLING_CALL_P (copy) = SIBLING_CALL_P (insn);
+         CONST_OR_PURE_CALL_P (copy) = CONST_OR_PURE_CALL_P (insn);
 
          /* Because the USAGE information potentially contains objects other
             than hard registers, we need to copy it.  */
@@ -2211,13 +2232,13 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
             this new block.  */
 
          if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
-             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL
-             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
-             && ((NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP
-                  && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_CONT)
-                 || (last_iteration && unroll_type != UNROLL_COMPLETELY)))
-           copy = emit_note (NOTE_SOURCE_FILE (insn),
-                             NOTE_LINE_NUMBER (insn));
+                  && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL
+                  && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
+                  && ((NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP
+                       && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_CONT)
+                      || (last_iteration
+                          && unroll_type != UNROLL_COMPLETELY)))
+           copy = emit_note_copy (insn);
          else
            copy = 0;
          break;
@@ -2263,11 +2284,11 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
             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_CONT)
-           emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
+             && ((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_CONT)))
+           emit_note_copy (insn);
        }
     }
 
@@ -2284,8 +2305,7 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
    won't fit in the immediate field of a PLUS insns.  */
 
 void
-emit_unrolled_add (dest_reg, src_reg, increment)
-     rtx dest_reg, src_reg, increment;
+emit_unrolled_add (rtx dest_reg, rtx src_reg, rtx increment)
 {
   rtx result;
 
@@ -2305,9 +2325,7 @@ emit_unrolled_add (dest_reg, src_reg, increment)
    and uses a negligible amount of CPU time on average.  */
 
 int
-back_branch_in_range_p (loop, insn)
-     const struct loop *loop;
-     rtx insn;
+back_branch_in_range_p (const struct loop *loop, rtx insn)
 {
   rtx p, q, target_insn;
   rtx loop_start = loop->start;
@@ -2353,9 +2371,7 @@ back_branch_in_range_p (loop, insn)
    value of giv's.  */
 
 static rtx
-fold_rtx_mult_add (mult1, mult2, add1, mode)
-     rtx mult1, mult2, add1;
-     enum machine_mode mode;
+fold_rtx_mult_add (rtx mult1, rtx mult2, rtx add1, enum machine_mode mode)
 {
   rtx temp, mult_res;
   rtx result;
@@ -2402,8 +2418,7 @@ fold_rtx_mult_add (mult1, mult2, add1, mode)
    if it can be calculated.  Otherwise, returns 0.  */
 
 rtx
-biv_total_increment (bl)
-     const struct iv_class *bl;
+biv_total_increment (const struct iv_class *bl)
 {
   struct induction *v;
   rtx result;
@@ -2454,10 +2469,8 @@ 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, unroll_number)
-     const struct loop *loop;
-     enum unroll_types unroll_type;
-     int unroll_number;
+find_splittable_regs (const struct loop *loop,
+                     enum unroll_types unroll_type, int unroll_number)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *bl;
@@ -2482,7 +2495,7 @@ find_splittable_regs (loop, unroll_type, unroll_number)
         it is unsafe to split the biv since it may not have the proper
         value on loop exit.  */
 
-      /* loop_number_exit_count is non-zero if the loop has an exit other than
+      /* loop_number_exit_count is nonzero if the loop has an exit other than
         a fall through at the end.  */
 
       biv_splittable = 1;
@@ -2507,7 +2520,7 @@ find_splittable_regs (loop, unroll_type, unroll_number)
            || GET_CODE (SET_SRC (tem)) != PLUS)
          biv_splittable = 0;
 
-      /* If final value is non-zero, then must emit an instruction which sets
+      /* If final value is nonzero, then must emit an instruction which sets
         the value of the biv to the proper value.  This is done after
         handling all of the givs, since some of them may need to use the
         biv's value in their initialization code.  */
@@ -2567,7 +2580,7 @@ find_splittable_regs (loop, unroll_type, unroll_number)
       result += find_splittable_givs (loop, bl, unroll_type, increment,
                                      unroll_number);
 
-      /* If final value is non-zero, then must emit an instruction which sets
+      /* If final value is nonzero, then must emit an instruction which sets
         the value of the biv to the proper value.  This is done after
         handling all of the givs, since some of them may need to use the
         biv's value in their initialization code.  */
@@ -2613,12 +2626,9 @@ find_splittable_regs (loop, unroll_type, unroll_number)
    Return the number of instructions that set splittable registers.  */
 
 static int
-find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
-     const struct loop *loop;
-     struct iv_class *bl;
-     enum unroll_types unroll_type;
-     rtx increment;
-     int unroll_number ATTRIBUTE_UNUSED;
+find_splittable_givs (const struct loop *loop, struct iv_class *bl,
+                     enum unroll_types unroll_type, rtx increment,
+                     int unroll_number ATTRIBUTE_UNUSED)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct induction *v, *v2;
@@ -2696,7 +2706,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
       /* Should emit insns after the loop if possible, as the biv final value
         code below does.  */
 
-      /* If the final value is non-zero, and the giv has not been reduced,
+      /* If the final value is nonzero, and the giv has not been reduced,
         then must emit an instruction to set the final value.  */
       if (final_value && !v->new_reg)
        {
@@ -2786,7 +2796,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
                  value = tem;
                }
 
-             splittable_regs[REGNO (v->new_reg)] = value;
+             splittable_regs[reg_or_subregno (v->new_reg)] = value;
            }
          else
            continue;
@@ -2820,7 +2830,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
          if (! v->ignore)
            count = REG_IV_CLASS (ivs, REGNO (v->src_reg))->biv_count;
 
-         splittable_regs_updates[REGNO (v->new_reg)] = count;
+         splittable_regs_updates[reg_or_subregno (v->new_reg)] = count;
        }
 
       result++;
@@ -2852,9 +2862,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
    it can search past if statements and other similar structures.  */
 
 static int
-reg_dead_after_loop (loop, reg)
-     const struct loop *loop;
-     rtx reg;
+reg_dead_after_loop (const struct loop *loop, rtx reg)
 {
   rtx insn, label;
   enum rtx_code code;
@@ -2890,11 +2898,15 @@ reg_dead_after_loop (loop, reg)
          code = GET_CODE (insn);
          if (GET_RTX_CLASS (code) == 'i')
            {
-             rtx set;
+             rtx set, note;
 
              if (reg_referenced_p (reg, PATTERN (insn)))
                return 0;
 
+             note = find_reg_equal_equiv_note (insn);
+             if (note && reg_overlap_mentioned_p (reg, XEXP (note, 0)))
+               return 0;
+
              set = single_set (insn);
              if (set && rtx_equal_p (SET_DEST (set), reg))
                break;
@@ -2924,9 +2936,7 @@ reg_dead_after_loop (loop, reg)
    the end of the loop.  If we can do it, return that value.  */
 
 rtx
-final_biv_value (loop, bl)
-     const struct loop *loop;
-     struct iv_class *bl;
+final_biv_value (const struct loop *loop, struct iv_class *bl)
 {
   unsigned HOST_WIDE_INT n_iterations = LOOP_INFO (loop)->n_iterations;
   rtx increment, tem;
@@ -2998,9 +3008,7 @@ final_biv_value (loop, bl)
    the end of the loop.  If we can do it, return that value.  */
 
 rtx
-final_giv_value (loop, v)
-     const struct loop *loop;
-     struct induction *v;
+final_giv_value (const struct loop *loop, struct induction *v)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *bl;
@@ -3127,9 +3135,7 @@ final_giv_value (loop, v)
    the SET_SRC of REG.  */
 
 static rtx
-loop_find_equiv_value (loop, reg)
-     const struct loop *loop;
-     rtx reg;
+loop_find_equiv_value (const struct loop *loop, rtx reg)
 {
   rtx loop_start = loop->start;
   rtx insn, set;
@@ -3182,8 +3188,7 @@ loop_find_equiv_value (loop, reg)
    the proper form.  */
 
 static rtx
-subtract_reg_term (op, reg)
-     rtx op, reg;
+subtract_reg_term (rtx op, rtx reg)
 {
   if (op == reg)
     return const0_rtx;
@@ -3203,8 +3208,7 @@ subtract_reg_term (op, reg)
    REG or a PLUS of a REG.  */
 
 static rtx
-find_common_reg_term (op0, op1)
-     rtx op0, op1;
+find_common_reg_term (rtx op0, rtx op1)
 {
   if ((GET_CODE (op0) == REG || GET_CODE (op0) == PLUS)
       && (GET_CODE (op1) == REG || GET_CODE (op1) == PLUS))
@@ -3240,8 +3244,7 @@ find_common_reg_term (op0, op1)
    be calculated, otherwise returns zero.  */
 
 unsigned HOST_WIDE_INT
-loop_iterations (loop)
-     struct loop *loop;
+loop_iterations (struct loop *loop)
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_ivs *ivs = LOOP_IVS (loop);
@@ -3615,7 +3618,7 @@ loop_iterations (loop)
 
          if (find_common_reg_term (temp, reg2))
            initial_value = temp;
-         else
+         else if (loop_invariant_p (loop, reg2))
            {
              /* Find what reg2 is equivalent to.  Hopefully it will
                 either be reg1 or reg1 plus a constant.  Let's ignore
@@ -3743,7 +3746,7 @@ loop_iterations (loop)
       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
+            comparison value.  Either we have an infinite loop, or
             we'll loop twice.  */
          if (increment == const0_rtx)
            return 0;
@@ -3869,9 +3872,7 @@ loop_iterations (loop)
    copying.  */
 
 static rtx
-remap_split_bivs (loop, x)
-     struct loop *loop;
-     rtx x;
+remap_split_bivs (struct loop *loop, rtx x)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   enum rtx_code code;
@@ -3939,12 +3940,8 @@ remap_split_bivs (loop, x)
    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;
+set_dominates_use (int regno, int first_uid, int last_uid, rtx copy_start,
+                  rtx copy_end)
 {
   int passed_jump = 0;
   rtx p = NEXT_INSN (copy_start);
@@ -3991,9 +3988,7 @@ set_dominates_use (regno, first_uid, last_uid, copy_start, copy_end)
    deleted so that we execute the single iteration.  */
 
 static rtx
-ujump_to_loop_cont (loop_start, loop_cont)
-     rtx loop_start;
-     rtx loop_cont;
+ujump_to_loop_cont (rtx loop_start, rtx loop_cont)
 {
   rtx x, label, label_ref;