OSDN Git Service

* unroll.c (copy_loop_body): Always ensure at least two insns
[pf3gnuchains/gcc-fork.git] / gcc / unroll.c
index bf03757..9c0109d 100644 (file)
@@ -1404,10 +1404,9 @@ precondition_loop_p (loop_start, loop_info,
       return 0;
     }
 
-  /* ??? Note that if iteration_info is modifed to allow GIV iterators
-     such as "while (i-- > 0)", the initial value will be one too small.
-     In this case, loop_iteration_var could be used to determine
-     the correct initial value, provided the loop has not been reversed.
+  /* Note that iteration_info biases the initial value for GIV iterators
+     such as "while (i-- > 0)" so that we can calculate the number of
+     iterations just like for BIV iterators.
 
      Also note that the absolute values of initial_value and
      final_value are unimportant as only their difference is used for
@@ -1672,6 +1671,12 @@ copy_loop_body (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
     {
@@ -2128,11 +2133,16 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
          break;
 
        case NOTE:
-         /* VTOP notes are valid only before the loop exit test.  If placed
-            anywhere else, loop may generate bad code.  */
+         /* VTOP and CONT notes are valid only before the loop exit test.
+            If placed anywhere else, loop may generate bad code.  */
+         /* BASIC_BLOCK notes exist to stabilize basic block structures with
+            the associated rtl.  We do not want to share the structure in 
+            this new block.  */
 
          if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
-             && (NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP
+             && 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));
@@ -2176,7 +2186,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
       for (insn = copy_notes_from; insn != loop_end; insn = NEXT_INSN (insn))
        {
          if (GET_CODE (insn) == NOTE
-             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
+             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
+             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)
            emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
        }
     }
@@ -2364,7 +2375,7 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
 
   /* 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) > reg_iv_type->num_elements)
+  if ((unsigned) REGNO (iteration_var) >= reg_iv_type->num_elements)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -2392,6 +2403,12 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
     }
   else if (REG_IV_TYPE (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)
+       abort ();
+
       /* Grab initial value, only useful if it is a constant.  */
       bl = reg_biv_class[REGNO (iteration_var)];
       *initial_value = bl->initial_value;
@@ -2400,34 +2417,46 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
     }
   else if (REG_IV_TYPE (REGNO (iteration_var)) == GENERAL_INDUCT)
     {
-#if 1
-      /* ??? The code below does not work because the incorrect number of
-        iterations is calculated when the biv is incremented after the giv
-        is set (which is the usual case).  This can probably be accounted
-        for by biasing the initial_value by subtracting the amount of the
-        increment that occurs between the giv set and the giv test.  However,
-        a giv as an iterator is very rare, so it does not seem worthwhile
-        to handle this.  */
-      /* ??? An example failure is: i = 6; do {;} while (i++ < 9).  */
-      if (loop_dump_stream)
-       fprintf (loop_dump_stream,
-                "Loop unrolling: Giv iterators are not handled.\n");
-      return;
-#else
-      /* Initial value is mult_val times the biv's initial value plus
-        add_val.  Only useful if it is a constant.  */
-      v = REG_IV_INFO (REGNO (iteration_var));
+      HOST_WIDE_INT offset = 0;
+      struct induction *v = REG_IV_INFO (REGNO (iteration_var));
+
+      if (REGNO (v->src_reg) >= max_reg_before_loop)
+       abort ();
+
       bl = reg_biv_class[REGNO (v->src_reg)];
-      *initial_value = fold_rtx_mult_add (v->mult_val, bl->initial_value,
-                                         v->add_val, v->mode);
 
       /* Increment value is mult_val times the increment value of the biv.  */
 
       *increment = biv_total_increment (bl, loop_start, loop_end);
       if (*increment)
-       *increment = fold_rtx_mult_add (v->mult_val, *increment, const0_rtx,
-                                       v->mode);
-#endif
+       {
+         struct induction *biv_inc;
+
+         *increment
+           = fold_rtx_mult_add (v->mult_val, *increment, const0_rtx, v->mode);
+         /* The caller assumes that one full increment has occured 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) .
+            Therefore, we bias the initial value by subtracting the amount of
+            the increment that occurs between the giv set and the giv test.  */
+         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);
+           }
+         offset *= INTVAL (v->mult_val);
+       }
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Loop unrolling: Giv iterator, initial value bias %ld.\n",
+                (long) offset);
+      /* Initial value is mult_val times the biv's initial value plus
+        add_val.  Only useful if it is a constant.  */
+      *initial_value
+       = fold_rtx_mult_add (v->mult_val,
+                            plus_constant (bl->initial_value, offset),
+                            v->add_val, v->mode);
     }
   else
     {
@@ -3626,10 +3655,10 @@ loop_iterations (loop_start, loop_end, loop_info)
       return 0;
     }
 
-  /* Loop iterations is always called before any new registers are created
-     now, so this should never occur.  */
+  /* The only new registers that care created before loop iterations are
+     givs made from biv increments, so this should never occur.  */
 
-  if (REGNO (iteration_var) >= max_reg_before_loop)
+  if ((unsigned) REGNO (iteration_var) >= reg_iv_type->num_elements)
     abort ();
 
   iteration_info (iteration_var, &initial_value, &increment,
@@ -3797,6 +3826,12 @@ loop_iterations (loop_start, loop_end, loop_info)
   loop_info->initial_equiv_value = initial_value;
   loop_info->final_equiv_value = final_value;
 
+  /* For EQ comparison loops, we don't have a valid final value.
+     Check this now so that we won't leave an invalid value if we
+     return early for any other reason.  */
+  if (comparison_code == EQ)
+      loop_info->final_equiv_value = loop_info->final_value = 0;
+
   if (increment == 0)
     {
       if (loop_dump_stream)
@@ -3807,7 +3842,11 @@ loop_iterations (loop_start, loop_end, loop_info)
 
   if (GET_CODE (increment) != CONST_INT)
     {
-      increment = loop_find_equiv_value (loop_start, increment);
+      /* If we have a REG, check to see if REG holds a constant value.  */
+      /* ??? Other RTL, such as (neg (reg)) is possible here, but it isn't
+        clear if it is worthwhile to try to handle such RTL.  */
+      if (GET_CODE (increment) == REG || GET_CODE (increment) == SUBREG)
+       increment = loop_find_equiv_value (loop_start, increment);
 
       if (GET_CODE (increment) != CONST_INT)
        {