OSDN Git Service

* cppinit.c (cpp_start_read): Free the imacros list as we
[pf3gnuchains/gcc-fork.git] / gcc / doloop.c
index cb2b67b..caf616c 100644 (file)
@@ -2,32 +2,32 @@
    Copyright (C) 1999, 2000 Free Software Foundation, Inc.
    Contributed by Michael P. Hayes (m.hayes@elec.canterbury.ac.nz)
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
 #include "rtl.h"
-#include "insn-flags.h"
 #include "flags.h"
 #include "expr.h"
 #include "loop.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
+#include "toplev.h"
 #include "tm_p.h"
 
 
@@ -281,7 +281,7 @@ doloop_valid_p (loop, jump_insn)
      statement within a loop will generate multiple loop exits.
      Another example of a loop that currently generates multiple exit
      targets is for (i = 0; i < (foo ? 8 : 4); i++) { }.  */
-  if (loop_info->has_multiple_exit_targets)
+  if (loop_info->has_multiple_exit_targets || loop->exit_count)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
@@ -415,14 +415,16 @@ doloop_modify (loop, iterations, iterations_max,
       fputs (" iterations).", loop_dump_stream);
     }
 
+  /* Emit the label that will delimit the top of the loop.
+     This has to be done before the delete_insn call below, to prevent
+     delete_insn from deleting too much.  */
+  emit_label_after (start_label, loop->top ? loop->top : loop->start);
+  LABEL_NUSES (start_label)++;
+
   /* Discard original jump to continue loop.  The original compare
      result may still be live, so it cannot be discarded explicitly.  */
   delete_insn (jump_insn);
 
-  /* Emit the label that will delimit the start of the loop.  */
-  emit_label_after (start_label, loop->start);
-  LABEL_NUSES (start_label)++;
-
   counter_reg = XEXP (condition, 0);
   if (GET_CODE (counter_reg) == PLUS)
     counter_reg = XEXP (counter_reg, 0);
@@ -466,9 +468,9 @@ doloop_modify (loop, iterations, iterations_max,
       if (GET_CODE (count) == CONST_INT)
        count = GEN_INT (INTVAL (count) - 1);
       else
-       count = expand_binop (GET_MODE (counter_reg), sub_optab,
-                             count, GEN_INT (1),
-                             0, 0, OPTAB_LIB_WIDEN);
+       count = expand_simple_binop (GET_MODE (counter_reg), MINUS,
+                                    count, GEN_INT (1),
+                                    0, 0, OPTAB_LIB_WIDEN);
     }
 
   /* Insert initialization of the count register into the loop header.  */
@@ -565,17 +567,22 @@ doloop_modify_runtime (loop, iterations_max,
                || comparison_code == NE);
 
   /* The number of iterations (prior to any loop unrolling) is given by:
-     (abs (final - initial) + abs_inc - 1) / abs_inc.
+
+       n = (abs (final - initial) + abs_inc - 1) / abs_inc.
 
      However, it is possible for the summation to overflow, and a
      safer method is:
 
-     abs (final - initial) / abs_inc + (abs (final - initial) % abs_inc) != 0
+       n = abs (final - initial) / abs_inc;
+       n += (abs (final - initial) % abs_inc) != 0;
 
      If the loop has been unrolled, then the loop body has been
-     preconditioned to iterate a multiple of unroll_number times.
-     The number of iterations of the loop body is simply:
-     abs (final - initial) / (abs_inc * unroll_number).
+     preconditioned to iterate a multiple of unroll_number times.  If
+     abs_inc is != 1, the full calculation is
+
+       t1 = abs_inc * unroll_number;
+       n = abs (final - initial) / t1;
+       n += (abs (final - initial) % t1) > t1 - abs_inc;
 
      The division and modulo operations can be avoided by requiring
      that the increment is a power of 2 (precondition_loop_p enforces
@@ -584,72 +591,58 @@ doloop_modify_runtime (loop, iterations_max,
 
   start_sequence ();
   /* abs (final - initial)  */
-  diff = expand_binop (mode, sub_optab,
-                      copy_rtx (neg_inc ? initial_value : final_value),
-                      copy_rtx (neg_inc ? final_value : initial_value),
-                      NULL_RTX, unsigned_p, OPTAB_LIB_WIDEN);
+  diff = expand_simple_binop (mode, MINUS,
+                             copy_rtx (neg_inc ? initial_value : final_value),
+                             copy_rtx (neg_inc ? final_value : initial_value),
+                             NULL_RTX, unsigned_p, OPTAB_LIB_WIDEN);
 
-  if (loop_info->unroll_number == 1)
+  if (abs_inc * loop_info->unroll_number != 1)
     {
+      int shift_count;
+      rtx extra;
+      rtx label;
+      unsigned HOST_WIDE_INT limit;
+
+      shift_count = exact_log2 (abs_inc * loop_info->unroll_number);
+      if (shift_count < 0)
+       abort ();
+
+      /* abs (final - initial) / (abs_inc * unroll_number)  */
+      iterations = expand_simple_binop (GET_MODE (diff), LSHIFTRT,
+                                       diff, GEN_INT (shift_count),
+                                       NULL_RTX, 1,
+                                       OPTAB_LIB_WIDEN);
+
       if (abs_inc != 1)
        {
-         int shift_count;
-         rtx extra;
-         rtx label;
-
-         shift_count = exact_log2 (abs_inc);
-         if (shift_count < 0)
-           abort ();
-
-         /* abs (final - initial) / abs_inc  */
-         iterations = expand_binop (GET_MODE (diff), lshr_optab,
-                                    diff, GEN_INT (shift_count),
-                                    NULL_RTX, 1,
-                                    OPTAB_LIB_WIDEN);
-
-         /* abs (final - initial) % abs_inc  */
-         extra = expand_binop (GET_MODE (iterations), and_optab,
-                               diff, GEN_INT (abs_inc - 1),
-                               NULL_RTX, 1,
-                               OPTAB_LIB_WIDEN);
-
-         /* If (abs (final - initial) % abs_inc == 0) jump past
-            following increment instruction.  */
+         /* abs (final - initial) % (abs_inc * unroll_number)  */
+         rtx count = GEN_INT (abs_inc * loop_info->unroll_number - 1);
+         extra = expand_simple_binop (GET_MODE (iterations), AND,
+                                      diff, count, NULL_RTX, 1,
+                                      OPTAB_LIB_WIDEN);
+
+         /* If (abs (final - initial) % (abs_inc * unroll_number)
+              <= abs_inc * (unroll - 1)),
+            jump past following increment instruction.  */
          label = gen_label_rtx();
-         emit_cmp_and_jump_insns (extra, const0_rtx, EQ, NULL_RTX,
+         limit = abs_inc * (loop_info->unroll_number - 1);
+         emit_cmp_and_jump_insns (extra, GEN_INT (limit),
+                                  limit == 0 ? EQ : LEU, NULL_RTX,
                                   GET_MODE (extra), 0, 0, label);
          JUMP_LABEL (get_last_insn ()) = label;
          LABEL_NUSES (label)++;
 
          /* Increment the iteration count by one.  */
-         iterations = expand_binop (GET_MODE (iterations), add_optab,
-                                    iterations, GEN_INT (1),
-                                    iterations, 1,
-                                    OPTAB_LIB_WIDEN);
+         iterations = expand_simple_binop (GET_MODE (iterations), PLUS,
+                                           iterations, GEN_INT (1),
+                                           iterations, 1,
+                                           OPTAB_LIB_WIDEN);
 
          emit_label (label);
        }
-      else
-       iterations = diff;
     }
   else
-    {
-      int shift_count;
-
-      /* precondition_loop_p has preconditioned the loop so that the
-        iteration count of the loop body is always a power of 2.
-        Since we won't get an overflow calculating the loop count,
-        the code we emit is simpler.  */
-      shift_count = exact_log2 (loop_info->unroll_number * abs_inc);
-      if (shift_count < 0)
-       abort ();
-
-      iterations = expand_binop (GET_MODE (diff), lshr_optab,
-                                diff, GEN_INT (shift_count),
-                                NULL_RTX, 1,
-                                OPTAB_LIB_WIDEN);
-    }
-
+    iterations = diff;
 
   /* If there is a NOTE_INSN_LOOP_VTOP, we have a `for' or `while'
      style loop, with a loop exit test at the start.  Thus, we can