[PATCH] Fix (X & C1) | C2 folding (PR tree-optimization/52286)
Richard Guenther
richard.guenther@gmail.com
Mon Feb 20 10:17:00 GMT 2012
On Fri, Feb 17, 2012 at 2:50 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> The following testcase is miscompiled (by CCP, or, if -fno-tree-ccp,
> by VRP), because the (X & C1) | C2 folding changes the C1 constant
> into an integer constant with most significant bit set, but not
> sign-extended into the double_int. Fixed by using double_int_to_tree
> which extends it properly, instead of build_int_cst_wide.
> Instead of creating a double_int from the hi3/lo3 pair I've changed
> the code to actually work on double_ints.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Ok.
Thanks,
Richard.
> 2012-02-17 Jakub Jelinek <jakub@redhat.com>
>
> PR tree-optimization/52286
> * fold-const.c (fold_binary_loc): For (X & C1) | C2
> optimization use double_int_to_tree instead of build_int_cst_wide,
> rewrite to use double_int vars.
>
> * gcc.c-torture/execute/pr52286.c: New test.
>
> --- gcc/fold-const.c.jj 2012-02-16 20:04:34.000000000 +0100
> +++ gcc/fold-const.c 2012-02-17 12:05:46.559700551 +0100
> @@ -10959,66 +10959,50 @@ fold_binary_loc (location_t loc,
> && TREE_CODE (arg1) == INTEGER_CST
> && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
> {
> - unsigned HOST_WIDE_INT hi1, lo1, hi2, lo2, hi3, lo3, mlo, mhi;
> + double_int c1, c2, c3, msk;
> int width = TYPE_PRECISION (type), w;
> - hi1 = TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1));
> - lo1 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1));
> - hi2 = TREE_INT_CST_HIGH (arg1);
> - lo2 = TREE_INT_CST_LOW (arg1);
> + c1 = tree_to_double_int (TREE_OPERAND (arg0, 1));
> + c2 = tree_to_double_int (arg1);
>
> /* If (C1&C2) == C1, then (X&C1)|C2 becomes (X,C2). */
> - if ((hi1 & hi2) == hi1 && (lo1 & lo2) == lo1)
> + if (double_int_equal_p (double_int_and (c1, c2), c1))
> return omit_one_operand_loc (loc, type, arg1,
> - TREE_OPERAND (arg0, 0));
> + TREE_OPERAND (arg0, 0));
>
> - if (width > HOST_BITS_PER_WIDE_INT)
> - {
> - mhi = (unsigned HOST_WIDE_INT) -1
> - >> (2 * HOST_BITS_PER_WIDE_INT - width);
> - mlo = -1;
> - }
> - else
> - {
> - mhi = 0;
> - mlo = (unsigned HOST_WIDE_INT) -1
> - >> (HOST_BITS_PER_WIDE_INT - width);
> - }
> + msk = double_int_mask (width);
>
> /* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2. */
> - if ((~(hi1 | hi2) & mhi) == 0 && (~(lo1 | lo2) & mlo) == 0)
> + if (double_int_zero_p (double_int_and_not (msk,
> + double_int_ior (c1, c2))))
> return fold_build2_loc (loc, BIT_IOR_EXPR, type,
> - TREE_OPERAND (arg0, 0), arg1);
> + TREE_OPERAND (arg0, 0), arg1);
>
> /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2,
> unless (C1 & ~C2) | (C2 & C3) for some C3 is a mask of some
> mode which allows further optimizations. */
> - hi1 &= mhi;
> - lo1 &= mlo;
> - hi2 &= mhi;
> - lo2 &= mlo;
> - hi3 = hi1 & ~hi2;
> - lo3 = lo1 & ~lo2;
> + c1 = double_int_and (c1, msk);
> + c2 = double_int_and (c2, msk);
> + c3 = double_int_and_not (c1, c2);
> for (w = BITS_PER_UNIT;
> w <= width && w <= HOST_BITS_PER_WIDE_INT;
> w <<= 1)
> {
> unsigned HOST_WIDE_INT mask
> = (unsigned HOST_WIDE_INT) -1 >> (HOST_BITS_PER_WIDE_INT - w);
> - if (((lo1 | lo2) & mask) == mask
> - && (lo1 & ~mask) == 0 && hi1 == 0)
> + if (((c1.low | c2.low) & mask) == mask
> + && (c1.low & ~mask) == 0 && c1.high == 0)
> {
> - hi3 = 0;
> - lo3 = mask;
> + c3 = uhwi_to_double_int (mask);
> break;
> }
> }
> - if (hi3 != hi1 || lo3 != lo1)
> + if (!double_int_equal_p (c3, c1))
> return fold_build2_loc (loc, BIT_IOR_EXPR, type,
> - fold_build2_loc (loc, BIT_AND_EXPR, type,
> - TREE_OPERAND (arg0, 0),
> - build_int_cst_wide (type,
> - lo3, hi3)),
> - arg1);
> + fold_build2_loc (loc, BIT_AND_EXPR, type,
> + TREE_OPERAND (arg0, 0),
> + double_int_to_tree (type,
> + c3)),
> + arg1);
> }
>
> /* (X & Y) | Y is (X, Y). */
> --- gcc/testsuite/gcc.c-torture/execute/pr52286.c.jj 2012-02-17 12:09:41.131621700 +0100
> +++ gcc/testsuite/gcc.c-torture/execute/pr52286.c 2012-02-17 12:09:22.000000000 +0100
> @@ -0,0 +1,14 @@
> +/* PR tree-optimization/52286 */
> +
> +extern void abort (void);
> +
> +int
> +main ()
> +{
> + int a, b;
> + asm ("" : "=r" (a) : "0" (0));
> + b = (~a | 1) & -2038094497;
> + if (b >= 0)
> + abort ();
> + return 0;
> +}
>
> Jakub
More information about the Gcc-patches
mailing list