OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / unroll.c
index f796c59..034fe52 100644 (file)
@@ -1,5 +1,5 @@
 /* Try to unroll loops, and split induction variables.
-   Copyright (C) 1992, 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1992, 93, 94, 95, 97, 1998 Free Software Foundation, Inc.
    Contributed by James E. Wilson, Cygnus Support/UC Berkeley.
 
 This file is part of GNU CC.
@@ -147,7 +147,7 @@ struct _factor { int factor, count; } factors[NUM_FACTORS]
 enum unroll_types { UNROLL_COMPLETELY, UNROLL_MODULO, UNROLL_NAIVE };
 
 #include "config.h"
-#include <stdio.h>
+#include "system.h"
 #include "rtl.h"
 #include "insn-config.h"
 #include "integrate.h"
@@ -156,6 +156,7 @@ enum unroll_types { UNROLL_COMPLETELY, UNROLL_MODULO, UNROLL_NAIVE };
 #include "flags.h"
 #include "expr.h"
 #include "loop.h"
+#include "toplev.h"
 
 /* This controls which loops are unrolled, and by how much we unroll
    them.  */
@@ -188,16 +189,16 @@ static int *splittable_regs_updates;
 /* Values describing the current loop's iteration variable.  These are set up
    by loop_iterations, and used by precondition_loop_p.  */
 
-static rtx loop_iteration_var;
-static rtx loop_initial_value;
-static rtx loop_increment;
-static rtx loop_final_value;
-static enum rtx_code loop_comparison_code;
+rtx loop_iteration_var;
+rtx loop_initial_value;
+rtx loop_increment;
+rtx loop_final_value;
+enum rtx_code loop_comparison_code;
 
 /* Forward declarations.  */
 
 static void init_reg_map PROTO((struct inline_remap *, int));
-static int precondition_loop_p PROTO((rtx *, rtx *, rtx *, rtx, rtx));
+static int precondition_loop_p PROTO((rtx *, rtx *, rtx *, rtx));
 static rtx calculate_giv_inc PROTO((rtx, rtx, int));
 static rtx initial_reg_note_copy PROTO((rtx, struct inline_remap *));
 static void final_reg_note_copy PROTO((rtx, struct inline_remap *));
@@ -210,6 +211,7 @@ static int find_splittable_givs PROTO((struct iv_class *,enum unroll_types,
                                       rtx, rtx, rtx, int));
 static int reg_dead_after_loop PROTO((rtx, rtx, rtx));
 static rtx fold_rtx_mult_add PROTO((rtx, rtx, rtx, enum machine_mode));
+static int verify_addresses PROTO((struct induction *, rtx, int));
 static rtx remap_split_bivs PROTO((rtx));
 
 /* Try to unroll one loop and split induction variables in the loop.
@@ -235,7 +237,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
   int i, j, temp;
   int unroll_number = 1;
   rtx copy_start, copy_end;
-  rtx insn, copy, sequence, pattern, tem;
+  rtx insn, sequence, pattern, tem;
   int max_labelno, max_insnno;
   rtx insert_before;
   struct inline_remap *map;
@@ -311,8 +313,11 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
     loop_n_iterations = 0;
 
   if (loop_dump_stream && loop_n_iterations > 0)
-    fprintf (loop_dump_stream,
-            "Loop unrolling: %d iterations.\n", loop_n_iterations);
+    {
+      fputs ("Loop unrolling: ", loop_dump_stream);
+      fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, loop_n_iterations);
+      fputs (" iterations.\n", loop_dump_stream);
+    }
 
   /* Find and save a pointer to the last nonnote insn in the loop.  */
 
@@ -426,15 +431,34 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
   if (unroll_type == UNROLL_COMPLETELY || unroll_type == UNROLL_MODULO)
     {
-      /* Loops of these types should never start with a jump down to
-        the exit condition test.  For now, check for this case just to
-        be sure.  UNROLL_NAIVE loops can be of this form, this case is
-        handled below.  */
+      /* Loops of these types can start with jump down to the exit condition
+        in rare circumstances.
+
+        Consider a pair of nested loops where the inner loop is part
+        of the exit code for the outer loop.
+
+        In this case jump.c will not duplicate the exit test for the outer
+        loop, so it will start with a jump to the exit code.
+
+        Then consider if the inner loop turns out to iterate once and
+        only once.  We will end up deleting the jumps associated with
+        the inner loop.  However, the loop notes are not removed from
+        the instruction stream.
+
+        And finally assume that we can compute the number of iterations
+        for the outer loop.
+
+        In this case unroll may want to unroll the outer loop even though
+        it starts with a jump to the outer loop's exit code.
+
+        We could try to optimize this case, but it hardly seems worth it.
+        Just return without unrolling the loop in such cases.  */
+
       insn = loop_start;
       while (GET_CODE (insn) != CODE_LABEL && GET_CODE (insn) != JUMP_INSN)
        insn = NEXT_INSN (insn);
       if (GET_CODE (insn) == JUMP_INSN)
-       abort ();
+       return;
     }
 
   if (unroll_type == UNROLL_COMPLETELY)
@@ -686,6 +710,8 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
 
   for (insn = copy_start; insn != loop_end; insn = NEXT_INSN (insn))
     {
+      rtx note;
+
       if (GET_CODE (insn) == CODE_LABEL)
        local_label[CODE_LABEL_NUMBER (insn)] = 1;
       else if (GET_CODE (insn) == JUMP_INSN)
@@ -711,6 +737,9 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
                }
            }
        }
+      else if ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)))
+       set_label_in_map (map, CODE_LABEL_NUMBER (XEXP (note, 0)),
+                         XEXP (note, 0));
     }
 
   /* Allocate space for the insn map.  */
@@ -829,9 +858,9 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
       rtx initial_value, final_value, increment;
 
       if (precondition_loop_p (&initial_value, &final_value, &increment,
-                              loop_start, loop_end))
+                              loop_start))
        {
-         register rtx diff, temp;
+         register rtx diff ;
          enum machine_mode mode;
          rtx *labels;
          int abs_inc, neg_inc;
@@ -1053,7 +1082,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
                  {
                    map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
                    record_base_value (REGNO (map->reg_map[j]),
-                                      regno_reg_rtx[j]);
+                                      regno_reg_rtx[j], 0);
                  }
              /* The last copy needs the compare/branch insns at the end,
                 so reset copy_end here if the loop ends with a conditional
@@ -1098,13 +1127,6 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
          /* Set unroll type to MODULO now.  */
          unroll_type = UNROLL_MODULO;
          loop_preconditioned = 1;
-
-#ifdef HAIFA
-         /* Fix the initial value for the loop as needed.  */
-         if (loop_n_iterations <= 0)
-           loop_start_value [uid_loop_num [INSN_UID (loop_start)]]
-             = initial_value;
-#endif
        }
     }
 
@@ -1215,7 +1237,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
          {
            map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
            record_base_value (REGNO (map->reg_map[j]),
-                              regno_reg_rtx[j]);
+                              regno_reg_rtx[j], 0);
          }
 
       /* If loop starts with a branch to the test, then fix it so that
@@ -1228,7 +1250,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
          tem = get_label_from_map (map,
                                    CODE_LABEL_NUMBER
                                    (XEXP (SET_SRC (pattern), 0)));
-         SET_SRC (pattern) = gen_rtx (LABEL_REF, VOIDmode, tem);
+         SET_SRC (pattern) = gen_rtx_LABEL_REF (VOIDmode, tem);
 
          /* Set the jump label so that it can be used by later loop unrolling
             passes.  */
@@ -1297,10 +1319,9 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
    whether divide is cheap.  */
 
 static int
-precondition_loop_p (initial_value, final_value, increment, loop_start,
-                    loop_end)
+precondition_loop_p (initial_value, final_value, increment, loop_start)
      rtx *initial_value, *final_value, *increment;
-     rtx loop_start, loop_end;
+     rtx loop_start;
 {
 
   if (loop_n_iterations > 0)
@@ -1310,9 +1331,13 @@ precondition_loop_p (initial_value, final_value, increment, loop_start,
       *final_value = GEN_INT (loop_n_iterations);
 
       if (loop_dump_stream)
-       fprintf (loop_dump_stream,
-                "Preconditioning: Success, number of iterations known, %d.\n",
-                loop_n_iterations);
+       {
+         fputs ("Preconditioning: Success, number of iterations known, ",
+                loop_dump_stream);
+         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC,
+                  loop_n_iterations);
+         fputs (".\n", loop_dump_stream);
+       }
       return 1;
     }
 
@@ -1452,6 +1477,7 @@ init_reg_map (map, maxregnum)
    to the iv.  This procedure reconstructs the pattern computing the iv;
    verifying that all operands are of the proper form.
 
+   PATTERN must be the result of single_set.
    The return value is the amount that the giv is incremented by.  */
 
 static rtx
@@ -1629,9 +1655,11 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
      rtx start_label, loop_end, insert_before, copy_notes_from;
 {
   rtx insn, pattern;
-  rtx tem, copy;
+  rtx set, tem, copy;
   int dest_reg_was_split, i;
+#ifdef HAVE_cc0
   rtx cc0_insn = 0;
+#endif
   rtx final_label = 0;
   rtx giv_inc, giv_dest_reg, giv_src_reg;
 
@@ -1674,15 +1702,15 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
             Do this before splitting the giv, since that may map the
             SET_DEST to a new register.  */
          
-         if (GET_CODE (pattern) == SET
-             && GET_CODE (SET_DEST (pattern)) == REG
-             && addr_combined_regs[REGNO (SET_DEST (pattern))])
+         if ((set = single_set (insn))
+             && GET_CODE (SET_DEST (set)) == REG
+             && addr_combined_regs[REGNO (SET_DEST (set))])
            {
              struct iv_class *bl;
              struct induction *v, *tv;
-             int regno = REGNO (SET_DEST (pattern));
+             int regno = REGNO (SET_DEST (set));
              
-             v = addr_combined_regs[REGNO (SET_DEST (pattern))];
+             v = addr_combined_regs[REGNO (SET_DEST (set))];
              bl = reg_biv_class[REGNO (v->src_reg)];
              
              /* Although the giv_inc amount is not needed here, we must call
@@ -1691,7 +1719,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                 we might accidentally delete insns generated immediately
                 below by emit_unrolled_add.  */
 
-             giv_inc = calculate_giv_inc (pattern, insn, regno);
+             giv_inc = calculate_giv_inc (set, insn, regno);
 
              /* Now find all address giv's that were combined with this
                 giv 'v'.  */
@@ -1765,11 +1793,11 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
          
          dest_reg_was_split = 0;
          
-         if (GET_CODE (pattern) == SET
-             && GET_CODE (SET_DEST (pattern)) == REG
-             && splittable_regs[REGNO (SET_DEST (pattern))])
+         if ((set = single_set (insn))
+             && GET_CODE (SET_DEST (set)) == REG
+             && splittable_regs[REGNO (SET_DEST (set))])
            {
-             int regno = REGNO (SET_DEST (pattern));
+             int regno = REGNO (SET_DEST (set));
              
              dest_reg_was_split = 1;
              
@@ -1777,9 +1805,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                 already computed above.  */
 
              if (giv_inc == 0)
-               giv_inc = calculate_giv_inc (pattern, insn, regno);
-             giv_dest_reg = SET_DEST (pattern);
-             giv_src_reg = SET_DEST (pattern);
+               giv_inc = calculate_giv_inc (set, insn, regno);
+             giv_dest_reg = SET_DEST (set);
+             giv_src_reg = SET_DEST (set);
 
              if (unroll_type == UNROLL_COMPLETELY)
                {
@@ -1857,7 +1885,12 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
                      tem = gen_reg_rtx (GET_MODE (giv_src_reg));
                      giv_dest_reg = tem;
                      map->reg_map[regno] = tem;
-                     record_base_value (REGNO (tem), giv_src_reg);
+                     record_base_value (REGNO (tem),
+                                        giv_inc == const0_rtx
+                                        ? giv_src_reg
+                                        : gen_rtx_PLUS (GET_MODE (giv_src_reg),
+                                                        giv_src_reg, giv_inc),
+                                        1);
                    }
                  else
                    map->reg_map[regno] = giv_src_reg;
@@ -1975,9 +2008,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
 
              /* Can't use the label_map for every insn, since this may be
                 the backward branch, and hence the label was not mapped.  */
-             if (GET_CODE (pattern) == SET)
+             if ((set = single_set (copy)))
                {
-                 tem = SET_SRC (pattern);
+                 tem = SET_SRC (set);
                  if (GET_CODE (tem) == LABEL_REF)
                    label = XEXP (tem, 0);
                  else if (GET_CODE (tem) == IF_THEN_ELSE)
@@ -2245,7 +2278,7 @@ fold_rtx_mult_add (mult1, mult2, add1, mode)
 
   mult_res = simplify_binary_operation (MULT, mode, mult1, mult2);
   if (! mult_res)
-    mult_res = gen_rtx (MULT, mode, mult1, mult2);
+    mult_res = gen_rtx_MULT (mode, mult1, mult2);
 
   /* Again, put the constant second.  */
   if (GET_CODE (add1) == CONST_INT)
@@ -2257,7 +2290,7 @@ fold_rtx_mult_add (mult1, mult2, add1, mode)
 
   result = simplify_binary_operation (PLUS, mode, add1, mult_res);
   if (! result)
-    result = gen_rtx (PLUS, mode, add1, mult_res);
+    result = gen_rtx_PLUS (mode, add1, mult_res);
 
   return result;
 }
@@ -2278,7 +2311,7 @@ biv_total_increment (bl, loop_start, loop_end)
 
   /* For increment, must check every instruction that sets it.  Each
      instruction must be executed only once each time through the loop.
-     To verify this, we check that the the insn is always executed, and that
+     To verify this, we check that the insn is always executed, and that
      there are no backward branches after the insn that branch to before it.
      Also, the insn must have a mult_val of one (to make sure it really is
      an increment).  */
@@ -2309,7 +2342,9 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
      rtx loop_start, loop_end;
 {
   struct iv_class *bl;
-  struct induction *v, *b;
+#if 0
+  struct induction *v;
+#endif
 
   /* Clear the result values, in case no answer can be found.  */
   *initial_value = 0;
@@ -2554,7 +2589,7 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
                {
                  rtx tem = gen_reg_rtx (bl->biv->mode);
 
-                 record_base_value (REGNO (tem), bl->biv->add_val);
+                 record_base_value (REGNO (tem), bl->biv->add_val, 0);
                  emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
                                    loop_start);
 
@@ -2611,7 +2646,7 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
                 this insn will always be executed, no matter how the loop
                 exits.  */
              rtx tem = gen_reg_rtx (bl->biv->mode);
-             record_base_value (REGNO (tem), bl->biv->add_val);
+             record_base_value (REGNO (tem), bl->biv->add_val, 0);
 
              emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
                                loop_start);
@@ -2647,14 +2682,16 @@ verify_addresses (v, giv_inc, unroll_number)
   rtx last_addr = plus_constant (v->dest_reg,
                                 INTVAL (giv_inc) * (unroll_number - 1));
 
-  /* First check to see if either address would fail.  */
-  if (! validate_change (v->insn, v->location, v->dest_reg, 0)
-      || ! validate_change (v->insn, v->location, last_addr, 0))
+  /* 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 will always
+  /* Now put things back the way they were before.  This should always
    succeed.  */
-  validate_change (v->insn, v->location, orig_addr, 0);
+  if (! validate_replace_rtx (*v->location, orig_addr, v->insn))
+    abort ();
 
   return ret;
 }
@@ -2792,7 +2829,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
            {
              rtx tem = gen_reg_rtx (bl->biv->mode);
 
-             record_base_value (REGNO (tem), bl->biv->add_val);
+             record_base_value (REGNO (tem), bl->biv->add_val, 0);
              emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
                                loop_start);
              biv_initial_value = tem;
@@ -2834,7 +2871,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                      || GET_CODE (XEXP (value, 1)) != CONST_INT))
                {
                  rtx tem = gen_reg_rtx (v->mode);
-                 record_base_value (REGNO (tem), v->add_val);
+                 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);
                  value = tem;
@@ -2893,8 +2930,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                     Emit insn to initialize its value before loop start.  */
 
                  rtx tem = gen_reg_rtx (v->mode);
-                 record_base_value (REGNO (tem), v->add_val);
-                 v->unrolled = 1;
+                 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,
@@ -2936,6 +2972,10 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                  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",
@@ -2943,13 +2983,17 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                      continue;
                    }
                  
+                 /* 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)),
+                 emit_insn_before (gen_rtx_SET (VOIDmode, tem,
+                                                copy_rtx (v->new_reg)),
                                    loop_start);
                  if (recog_memoized (PREV_INSN (loop_start)) < 0)
                    {
@@ -2982,6 +3026,10 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
                     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",
@@ -3109,7 +3157,7 @@ reg_dead_after_loop (reg, loop_start, loop_end)
   /* HACK: Must also search the loop fall through exit, create a label_ref
      here which points to the loop_end, and append the loop_number_exit_labels
      list to it.  */
-  label = gen_rtx (LABEL_REF, VOIDmode, loop_end);
+  label = gen_rtx_LABEL_REF (VOIDmode, loop_end);
   LABEL_NEXTREF (label) = loop_number_exit_labels[this_loop_num];
 
   for ( ; label; label = LABEL_NEXTREF (label))
@@ -3201,7 +3249,7 @@ final_biv_value (bl, loop_start, loop_end)
             case it is needed later.  */
 
          tem = gen_reg_rtx (bl->biv->mode);
-         record_base_value (REGNO (tem), bl->biv->add_val);
+         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);
@@ -3300,7 +3348,7 @@ final_giv_value (v, loop_start, loop_end)
 
          /* Put the final biv value in tem.  */
          tem = gen_reg_rtx (bl->biv->mode);
-         record_base_value (REGNO (tem), bl->biv->add_val);
+         record_base_value (REGNO (tem), bl->biv->add_val, 0);
          emit_iv_add_mult (increment, GEN_INT (loop_n_iterations),
                            bl->initial_value, tem, insert_before);