]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
backport: re PR rtl-optimization/7130 (miscompiled code for gcc-3.1 on powerpc-unknow...
authorAlan Modra <amodra@bigpond.net.au>
Tue, 17 Sep 2002 03:25:06 +0000 (03:25 +0000)
committerAlan Modra <amodra@gcc.gnu.org>
Tue, 17 Sep 2002 03:25:06 +0000 (12:55 +0930)
Merge from mainline.
2002-07-20  Alan Modra  <amodra@bigpond.net.au>
PR optimization/7130
* loop.h (struct loop_info): Add "preconditioned".
* unroll.c (unroll_loop): Set it.
* doloop.c (doloop_modify_runtime): Correct count for unrolled loops.

2002-06-24  Alan Modra  <amodra@bigpond.net.au>
PR optimization/6984
* doloop.c (doloop_valid_p): Correct comment.
(doloop_modify_runtime <abs_inc != 1>): Simplify.
(doloop_modify_runtime <do-while>): Don't emit code when NE.

From-SVN: r57225

gcc/ChangeLog
gcc/doloop.c
gcc/loop.h
gcc/unroll.c

index 2e643596af535b42c1f8da1f0ff7d1ef3dec0202..3baa584b53a2591efc87a85b2853799e78a1f742 100644 (file)
@@ -1,3 +1,18 @@
+2002-09-17  Alan Modra  <amodra@bigpond.net.au>
+
+       Merge from mainline.
+       2002-07-20  Alan Modra  <amodra@bigpond.net.au>
+       PR optimization/7130
+       * loop.h (struct loop_info): Add "preconditioned".
+       * unroll.c (unroll_loop): Set it.
+       * doloop.c (doloop_modify_runtime): Correct count for unrolled loops.
+
+       2002-06-24  Alan Modra  <amodra@bigpond.net.au>
+       PR optimization/6984
+       * doloop.c (doloop_valid_p): Correct comment.
+       (doloop_modify_runtime <abs_inc != 1>): Simplify.
+       (doloop_modify_runtime <do-while>): Don't emit code when NE.
+
 2002-09-16  Jeff Law <law@redhat.com>
 
         * libgcc2.c: Do not include machmode.h.
index 6c0185cafd55fc95823ecff8d349974398d7e6bd..4be8c6d05a3fa6187c2fa8023367775ff9bae5e2 100644 (file)
@@ -552,6 +552,7 @@ doloop_modify_runtime (loop, iterations_max,
 {
   const struct loop_info *loop_info = LOOP_INFO (loop);
   HOST_WIDE_INT abs_inc;
+  HOST_WIDE_INT abs_loop_inc;
   int neg_inc;
   rtx diff;
   rtx sequence;
@@ -591,13 +592,22 @@ doloop_modify_runtime (loop, iterations_max,
        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.  If
-     abs_inc is != 1, the full calculation is
+     But when abs_inc is a power of two, the summation won't overflow
+     except in cases where the loop never terminates.  So we don't
+     need to use this more costly calculation.
 
-       t1 = abs_inc * unroll_number;
-       n = abs (final - initial) / t1;
-       n += (abs (final - initial) % t1) > t1 - abs_inc;
+     If the loop has been unrolled, the full calculation is
+
+       t1 = abs_inc * unroll_number;           increment per loop
+       n = abs (final - initial) / t1;         full loops
+       n += (abs (final - initial) % t1) != 0; partial loop
+
+     However, in certain cases the unrolled loop will be preconditioned
+     by emitting copies of the loop body with conditional branches,
+     so that the unrolled loop is always a full loop and thus needs
+     no exit tests.  In this case we don't want to add the partial
+     loop count.  As above, when t1 is a power of two we don't need to
+     worry about overflow.
 
      The division and modulo operations can be avoided by requiring
      that the increment is a power of 2 (precondition_loop_p enforces
@@ -663,53 +673,27 @@ doloop_modify_runtime (loop, iterations_max,
        }
     }
 
-  if (abs_inc * loop_info->unroll_number != 1)
+  abs_loop_inc = abs_inc * loop_info->unroll_number;
+  if (abs_loop_inc != 1)
     {
       int shift_count;
-      rtx extra;
-      rtx label;
-      unsigned HOST_WIDE_INT limit;
 
-      shift_count = exact_log2 (abs_inc * loop_info->unroll_number);
+      shift_count = exact_log2 (abs_loop_inc);
       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)
-       {
-         /* 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 ();
-         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, label);
-         JUMP_LABEL (get_last_insn ()) = label;
-         LABEL_NUSES (label)++;
-
-         /* Increment the iteration count by one.  */
-         iterations = expand_simple_binop (GET_MODE (iterations), PLUS,
-                                           iterations, GEN_INT (1),
-                                           iterations, 1,
-                                           OPTAB_LIB_WIDEN);
+      if (!loop_info->preconditioned)
+       diff = expand_simple_binop (GET_MODE (diff), PLUS,
+                                   diff, GEN_INT (abs_loop_inc - 1),
+                                   diff, 1, OPTAB_LIB_WIDEN);
 
-         emit_label (label);
-       }
+      /* (abs (final - initial) + abs_inc * unroll_number - 1)
+        / (abs_inc * unroll_number)  */
+      diff = expand_simple_binop (GET_MODE (diff), LSHIFTRT,
+                                 diff, GEN_INT (shift_count),
+                                 diff, 1, OPTAB_LIB_WIDEN);
     }
-  else
-    iterations = diff;
+  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
@@ -722,17 +706,20 @@ doloop_modify_runtime (loop, iterations_max,
      iteration count to one if necessary.  */
   if (! loop->vtop)
     {
-      rtx label;
-
       if (loop_dump_stream)
        fprintf (loop_dump_stream, "Doloop: Do-while loop.\n");
 
-      /* A `do-while' loop must iterate at least once.  If the
-        iteration count is bogus, we set the iteration count to 1.
+      /* A `do-while' loop must iterate at least once.  For code like
+        i = initial; do { ... } while (++i < final);
+        we will calculate a bogus iteration count if initial > final.
+        So detect this and set the iteration count to 1.
         Note that if the loop has been unrolled, then the loop body
-        is guaranteed to execute at least once.  */
-      if (loop_info->unroll_number == 1)
+        is guaranteed to execute at least once.  Also, when the
+        comparison is NE, our calculated count will be OK.  */
+      if (loop_info->unroll_number == 1 && comparison_code != NE)
        {
+         rtx label;
+
          /*  Emit insns to test if the loop will immediately
              terminate and to set the iteration count to 1 if true.  */
          label = gen_label_rtx();
index 8e3a9351f36c7947d0ade34a3988ee08c06d5ca4..6d18b01f5bd582c0c315f26a63cb9ac3c26a8a4a 100644 (file)
@@ -314,6 +314,9 @@ struct loop_info
   int has_multiple_exit_targets;
   /* Nonzero if there is an indirect jump in the current function.  */
   int has_indirect_jump;
+  /* Whether loop unrolling has emitted copies of the loop body so
+     that the main loop needs no exit tests.  */
+  int preconditioned;
   /* Register or constant initial loop value.  */
   rtx initial_value;
   /* Register or constant value used for comparison test.  */
index 032d675a3b65dc21be6ab641426c70d4e705dda5..509636c0a6a89d89b0bfca55a3843d3bcddfc6ea 100644 (file)
@@ -1188,6 +1188,9 @@ unroll_loop (loop, insn_count, strength_reduce_p)
   /* Keep track of the unroll factor for the loop.  */
   loop_info->unroll_number = unroll_number;
 
+  /* And whether the loop has been preconditioned.  */
+  loop_info->preconditioned = 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