This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] unroll-loops and branch-count-reg fixes


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])++;
 	     }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]