This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] unroll-loops and branch-count-reg fixes
- To: gcc-patches at gcc dot gnu dot org
- Subject: [PATCH] unroll-loops and branch-count-reg fixes
- From: Zoltan Hidvegi <hzoli at hzoli dot 2y dot net>
- Date: Wed, 27 Jun 2001 17:26:59 -0500 (CDT)
The testcase below fails with -O2 -funroll-loops on all targets both with
gcc-2.95.2 and with gcc-3.0. There are really 2 bugs involved on targets
that use count register loops, such as the PowerPC. Also
void
do_loop(unsigned long c, char *m)
{
unsigned long i = 0;
do {
m[i] = 0;
} while (++i != c);
}
miscompiles on PowerPC with -O2, since for c == 0 the loop is executed
once instead of 2^32 times. The patch below should fix this and that
closes PR 3384. I made the diff to vanilla gcc-3.0.
I would appreciate if gcc-3.0.1 could have these fixes.
Thanks,
Zoli
compile this with -O2 -funroll-loops:
----------- START TESTCASE ------------
#define N 4
#define M 4*N
int printf(const char *format, ...);
typedef unsigned long ulong;
ulong
run_bug(ulong idx, ulong n)
{
ulong t = 0;
ulong i;
for (i = idx; i < n; i += N) {
t++;
}
return t;
}
int
main(void)
{
ulong hi = (~0ul >> 1) + 1;
ulong lo = hi - M;
ulong di, dj;
ulong err = 0;
for (di = 0; di != M; di++) {
for (dj = 0; dj != M; dj++) {
ulong i = lo - di;
ulong j = hi + dj;
ulong expect = (j-i)/N + !!((j-i) % N);
if (run_bug(i, j) != expect) {
err++;
printf("run_bug(%lu, %lu) != %lu\n", i, j, expect);
}
}
}
return err;
}
-------------- END TESTCASE -----------
2001-06-27 Zoltan Hidvegi <hzoli@hzoli.com>
* gcc/doloop.c (doloop_modify_runtime): fix branch-count-reg bugs
* gcc/unroll.c (unroll_loop): use insigned compare for unsigned
loops
--- gcc/doloop.c-3.0 Sat May 12 15:32:26 2001
+++ gcc/doloop.c Wed Jun 27 16:21:22 2001
@@ -645,10 +645,24 @@ doloop_modify_runtime (loop, iterations_
if (shift_count < 0)
abort ();
- iterations = expand_binop (GET_MODE (diff), lshr_optab,
- diff, GEN_INT (shift_count),
- NULL_RTX, 1,
- OPTAB_LIB_WIDEN);
+ if (abs_inc > 1)
+ {
+ iterations = expand_binop (GET_MODE (diff), add_optab,
+ diff, GEN_INT (abs_inc - 1),
+ NULL_RTX, 1,
+ OPTAB_LIB_WIDEN);
+ iterations = expand_binop (GET_MODE (iterations), lshr_optab,
+ iterations, GEN_INT (shift_count),
+ iterations, 1,
+ OPTAB_LIB_WIDEN);
+ }
+ else
+ {
+ iterations = expand_binop (GET_MODE (diff), lshr_optab,
+ diff, GEN_INT (shift_count),
+ NULL_RTX, 1,
+ OPTAB_LIB_WIDEN);
+ }
}
@@ -661,7 +675,7 @@ doloop_modify_runtime (loop, iterations_
not executed before the start of the loop. We need to determine
if the loop will terminate after the first pass and to limit the
iteration count to one if necessary. */
- if (! loop->vtop)
+ if (! loop->vtop && comparison_code != NE)
{
rtx label;
--- gcc/unroll.c-3.0 Sat Apr 21 13:43:40 2001
+++ gcc/unroll.c Wed Jun 27 15:32:37 2001
@@ -959,9 +959,14 @@ unroll_loop (loop, insn_count, strength_
if (loop_info->comparison_code != NE)
{
+ enum rtx_code cc = loop_info->comparison_code;
+ int unsigned_p = (cc == LEU ||
+ cc == GEU ||
+ cc == LTU ||
+ cc == GTU);
emit_cmp_and_jump_insns (initial_value, final_value,
- neg_inc ? LE : GE,
- NULL_RTX, mode, 0, 0, labels[1]);
+ neg_inc ? LE : GE, NULL_RTX,
+ mode, unsigned_p, 0, labels[1]);
JUMP_LABEL (get_last_insn ()) = labels[1];
LABEL_NUSES (labels[1])++;
}