[PATCH] Fold integer divisions to arithmetic shifts
Jakub Jelinek
jakub@redhat.com
Thu Oct 14 16:38:00 GMT 2010
On Thu, Oct 14, 2010 at 07:58:18PM +0400, Dmitry Melnik wrote:
> diff --git a/gcc/fold-const.c b/gcc/fold-const.c
> index 8146920..de0f350 100644
> --- a/gcc/fold-const.c
> +++ b/gcc/fold-const.c
> @@ -11599,6 +11599,22 @@ fold_binary_loc (location_t loc,
> return NULL_TREE;
>
> case TRUNC_DIV_EXPR:
> + /* Optimize (X & (-A)) / A where A is a power of 2,
> + to X >> log2(A) */
> + if (TREE_CODE (arg0) == BIT_AND_EXPR
> + && !TYPE_UNSIGNED (type)
> + && integer_pow2p (arg1) && tree_int_cst_sgn (arg1) > 0)
> + {
> + tree sum = fold_binary_loc (loc, PLUS_EXPR, TREE_TYPE (arg1),
> + arg1, TREE_OPERAND (arg0, 1));
> + if (sum && integer_zerop (sum))
> + return fold_build2_loc (loc, RSHIFT_EXPR, type,
> + TREE_OPERAND (arg0, 0),
> + build_int_cst (NULL_TREE,
> + exact_log2 (TREE_INT_CST_LOW (arg1))));
Consider
long long x = foo ();
x = (x & -0x200000000LL) / 0x200000000LL;
The above code would optimize this as
x = x >> -1;
on 32-bit HWI targets. Also, I think checking that arg1 is actually
INTEGER_CST would be desirable too (integer_pow2p can return true
even for COMPLEX_CST and then tree_int_cst_sgn accesses something the
COMPLEX_CST doesn't have).
Seems you've probably copied it from elsewhere which has a similar bug,
will file a PR and fix that:
extern void abort (void);
__attribute__((noinline)) unsigned long long
foo (unsigned long long x, int n)
{
return x / (0x200000000ULL << n);
}
volatile unsigned long long l = 0x40000000000ULL;
int
main (void)
{
if (foo (l, 1) != 0x100 || foo (l, 3) != 0x40)
abort ();
return 0;
}
fails on i686-linux at -O2 if 32-bit HWI, succeeds with 64-bit HWI or -m64.
Jakub
More information about the Gcc-patches
mailing list