summaryrefslogtreecommitdiff
path: root/gcc/doloop.c
diff options
context:
space:
mode:
authorbernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4>2001-08-05 16:20:43 +0000
committerbernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4>2001-08-05 16:20:43 +0000
commit0119aa69d6eaf224c2fe23e4c480c53cb5aa2a12 (patch)
tree9e444738631291cbf93ee94188a9050d2c51ebb5 /gcc/doloop.c
parent883b8160cbef20b4e6d609234e996f540303c019 (diff)
downloadgcc-0119aa69d6eaf224c2fe23e4c480c53cb5aa2a12.tar.gz
Fix computation of number of iterations with unrolling
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@44644 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/doloop.c')
-rw-r--r--gcc/doloop.c79
1 files changed, 35 insertions, 44 deletions
diff --git a/gcc/doloop.c b/gcc/doloop.c
index b9e8d8c68fb..1cd619762a6 100644
--- a/gcc/doloop.c
+++ b/gcc/doloop.c
@@ -567,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
@@ -591,34 +596,38 @@ doloop_modify_runtime (loop, iterations_max,
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_binop (GET_MODE (diff), lshr_optab,
+ 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 */
+ /* abs (final - initial) % (abs_inc * unroll_number) */
extra = expand_binop (GET_MODE (iterations), and_optab,
- diff, GEN_INT (abs_inc - 1),
+ diff, GEN_INT (abs_inc * loop_info->unroll_number - 1),
NULL_RTX, 1,
OPTAB_LIB_WIDEN);
- /* If (abs (final - initial) % abs_inc == 0) jump past
- following increment instruction. */
+ /* 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)++;
@@ -631,27 +640,9 @@ doloop_modify_runtime (loop, iterations_max,
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