OSDN Git Service

* config/mips/iris5.h (UNALIGNED_INT_ASM_OP,
[pf3gnuchains/gcc-fork.git] / gcc / unroll.c
index b22d01f..9a09f5d 100644 (file)
@@ -1,5 +1,5 @@
 /* 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
    Free Software Foundation, Inc.
    Contributed by James E. Wilson, Cygnus Support/UC Berkeley.
 
@@ -167,6 +167,7 @@ enum unroll_types
 #include "toplev.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
+#include "predict.h"
 
 /* This controls which loops are unrolled, and by how much we unroll
    them.  */
@@ -201,12 +202,12 @@ 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));
@@ -222,19 +223,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);
@@ -768,7 +766,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));
     }
@@ -965,6 +963,7 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
              emit_cmp_and_jump_insns (initial_value, final_value,
                                       neg_inc ? LE : GE,
                                       NULL_RTX, mode, 0, 0, labels[1]);
+             predict_insn_def (get_last_insn (), PRED_LOOP_CONDITION, NOT_TAKEN);
              JUMP_LABEL (get_last_insn ()) = labels[1];
              LABEL_NUSES (labels[1])++;
            }
@@ -1010,6 +1009,8 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
                                       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,
@@ -1045,7 +1046,7 @@ unroll_loop (loop, insn_count, end_insert_before, strength_reduce_p)
 
          sequence = gen_sequence ();
          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,
@@ -1163,8 +1164,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
@@ -1385,7 +1385,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,
@@ -1663,13 +1670,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 +1688,38 @@ 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))];
 
-  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))];
+             /* If we failed to remap the note, something is awry.  */
+             if (!insn)
+               abort ();
+
+             XEXP (note, 0) = insn;
+           }
+       }
+
+      notesp = &XEXP (note, 1);
+    }
 }
 
 /* Copy each instruction in the loop, substituting from map as appropriate.
@@ -2216,7 +2246,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);
 
@@ -2254,7 +2284,7 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
 
   tem = gen_sequence ();
   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
@@ -2381,7 +2411,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;
@@ -2431,10 +2461,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,8 +2473,6 @@ 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->list; bl; bl = bl->next)
     {
@@ -2469,7 +2496,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 +2539,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 +2585,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 +2597,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",
@@ -2717,9 +2741,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 +2775,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,8 +2817,8 @@ 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;
                }
 
@@ -2923,17 +2945,15 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
                     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);
+                 loop_insn_hoist (loop, gen_rtx_SET (VOIDmode, tem,
+                                                     copy_rtx (v->new_reg)));
                  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.  */
+                        We must calculate it from NEW_REG.  */
                      delete_insn (PREV_INSN (loop->start));
 
                      start_sequence ();
@@ -2942,7 +2962,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
                        emit_move_insn (tem, ret);
                      sequence = gen_sequence ();
                      end_sequence ();
-                     emit_insn_before (sequence, loop->start);
+                     loop_insn_hoist (loop, sequence);
 
                      if (loop_dump_stream)
                        fprintf (loop_dump_stream,
@@ -3140,7 +3160,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 +3201,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 +3238,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;
 
@@ -3279,15 +3295,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;
@@ -3304,12 +3318,12 @@ final_giv_value (loop, v)
                                        OPTAB_LIB_WIDEN);
                    seq = gen_sequence ();
                    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,
@@ -3464,7 +3478,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;
@@ -3597,6 +3612,13 @@ loop_iterations (loop)
       /* 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,6 +3631,14 @@ loop_iterations (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.  */
@@ -3852,7 +3882,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;
@@ -3866,7 +3896,7 @@ 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;
@@ -3883,7 +3913,7 @@ loop_iterations (loop)
        {
          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;
@@ -3949,17 +3979,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