summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramodra <amodra@138bc75d-0d04-0410-961f-82ee72b054a4>2002-07-20 00:31:15 +0000
committeramodra <amodra@138bc75d-0d04-0410-961f-82ee72b054a4>2002-07-20 00:31:15 +0000
commit4db1469f863b2b9d82eff8d112a9471a4c94b079 (patch)
tree94eedd6796f702b3e750b75344a9180da4a76c79
parenta7ae1e597777179c8b1545a3b56518781f1de909 (diff)
downloadgcc-4db1469f863b2b9d82eff8d112a9471a4c94b079.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@55598 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/doloop.c30
-rw-r--r--gcc/loop.h3
-rw-r--r--gcc/unroll.c3
4 files changed, 32 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 69403e0b4db..8fd107b8107 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+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-07-19 Zack Weinberg <zack@codesourcery.com>
* rtl.def (CODE_LABEL): Remove slot 8.
diff --git a/gcc/doloop.c b/gcc/doloop.c
index ee5b788a911..9bddb92ed23 100644
--- a/gcc/doloop.c
+++ b/gcc/doloop.c
@@ -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;
@@ -595,13 +596,18 @@ doloop_modify_runtime (loop, iterations_max,
except in cases where the loop never terminates. So we don't
need to use this more costly calculation.
- 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
+ If the loop has been unrolled, the full calculation is
- t1 = abs_inc * unroll_number;
- n = abs (final - initial) / t1;
- n += (abs (final - initial) % t1) > t1 - abs_inc;
+ 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
@@ -667,20 +673,22 @@ 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;
- shift_count = exact_log2 (abs_inc * loop_info->unroll_number);
+ shift_count = exact_log2 (abs_loop_inc);
if (shift_count < 0)
abort ();
- if (abs_inc != 1)
+ if (!loop_info->preconditioned)
diff = expand_simple_binop (GET_MODE (diff), PLUS,
- diff, GEN_INT (abs_inc - 1),
+ diff, GEN_INT (abs_loop_inc - 1),
diff, 1, OPTAB_LIB_WIDEN);
- /* (abs (final - initial) + abs_inc - 1) / (abs_inc * unroll_number) */
+ /* (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);
diff --git a/gcc/loop.h b/gcc/loop.h
index 4f4dc4160c1..631352fee6d 100644
--- a/gcc/loop.h
+++ b/gcc/loop.h
@@ -316,6 +316,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. */
diff --git a/gcc/unroll.c b/gcc/unroll.c
index e0b0d36579d..c8201ed6336 100644
--- a/gcc/unroll.c
+++ b/gcc/unroll.c
@@ -1135,6 +1135,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