This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: integer_each_onep + vector bug
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: Marc Glisse <marc dot glisse at inria dot fr>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 12 Sep 2014 12:21:37 +0200
- Subject: Re: integer_each_onep + vector bug
- Authentication-results: sourceware.org; auth=none
- References: <alpine dot DEB dot 2 dot 02 dot 1409121142380 dot 13048 at stedding dot saclay dot inria dot fr>
On Fri, Sep 12, 2014 at 12:04 PM, Marc Glisse <marc.glisse@inria.fr> wrote:
> Hello,
>
> here is a new predicate which tests if a number is 1, or (for vector and
> complex) a collection of 1. The only difference with integer_onep should be
> for complex where it wants 1+i and not 1. The main use would be in the match
> branch, so I didn't waste too much time adding many uses, I just added a
> couple (so the function won't be garbage collected in some refactoring)
> though I wasn't able to create a testcase (for complex int, '&' or '^' are
> rejected and '~' means conjugate).
>
> While looking for potential uses for integer_each_onep, I couldn't help
> noticing a few wrong optimizations for vectors, that I am fixing at the same
> time.
Yeah, the transforms you disable are questionable for GIMPLE anyway
as (X & 1) == 0 needs to have boolean type there and we like the
other forms more. This looks like a transform targeted at RTL expansion
to me (or one that is profitable if the expression feeds a conditional
which we can merge it into - like the (~X & Y) -> X < Y transforms
tree-ssa-forwprop.c does.
Ok.
Thanks,
Richard.
>
> Bootstrap+testsuite on x86_64-linux-gnu.
>
>
> 2014-09-12 Marc Glisse <marc.glisse@inria.fr>
>
> gcc/
> * tree.c (integer_each_onep): New function.
> * tree.h (integer_each_onep): Declare it.
> * fold-const.c (fold_binary_loc): Use it for ~A + 1 to -A and
> -A - 1 to ~A. Disable (X & 1) ^ 1, (X ^ 1) & 1 and ~X & 1 to
> (X & 1) == 0 for vector and complex.
> gcc/testsuite/
> * gcc.dg/vec-andxor1.c: New file.
>
>
> --
> Marc Glisse
> Index: fold-const.c
> ===================================================================
> --- fold-const.c (revision 215179)
> +++ fold-const.c (working copy)
> @@ -10085,21 +10085,21 @@ fold_binary_loc (location_t loc,
> && (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
> return fold_build2_loc (loc, MINUS_EXPR, type,
> fold_convert_loc (loc, type, arg1),
> fold_convert_loc (loc, type,
> TREE_OPERAND (arg0, 0)));
>
> if (INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type))
> {
> /* Convert ~A + 1 to -A. */
> if (TREE_CODE (arg0) == BIT_NOT_EXPR
> - && integer_onep (arg1))
> + && integer_each_onep (arg1))
> return fold_build1_loc (loc, NEGATE_EXPR, type,
> fold_convert_loc (loc, type,
> TREE_OPERAND (arg0, 0)));
>
> /* ~X + X is -1. */
> if (TREE_CODE (arg0) == BIT_NOT_EXPR
> && !TYPE_OVERFLOW_TRAPS (type))
> {
> tree tem = TREE_OPERAND (arg0, 0);
>
> @@ -10612,23 +10612,22 @@ fold_binary_loc (location_t loc,
> /* (-A) - B -> (-B) - A where B is easily negated and we can swap.
> */
> if (TREE_CODE (arg0) == NEGATE_EXPR
> && negate_expr_p (arg1)
> && reorder_operands_p (arg0, arg1))
> return fold_build2_loc (loc, MINUS_EXPR, type,
> fold_convert_loc (loc, type,
> negate_expr (arg1)),
> fold_convert_loc (loc, type,
> TREE_OPERAND (arg0, 0)));
> /* Convert -A - 1 to ~A. */
> - if (TREE_CODE (type) != COMPLEX_TYPE
> - && TREE_CODE (arg0) == NEGATE_EXPR
> - && integer_onep (arg1)
> + if (TREE_CODE (arg0) == NEGATE_EXPR
> + && integer_each_onep (arg1)
> && !TYPE_OVERFLOW_TRAPS (type))
> return fold_build1_loc (loc, BIT_NOT_EXPR, type,
> fold_convert_loc (loc, type,
> TREE_OPERAND (arg0, 0)));
>
> /* Convert -1 - A to ~A. */
> if (TREE_CODE (type) != COMPLEX_TYPE
> && integer_all_onesp (arg0))
> return fold_build1_loc (loc, BIT_NOT_EXPR, type, op1);
>
> @@ -11377,20 +11376,21 @@ fold_binary_loc (location_t loc,
> /* Convert ~X ^ C to X ^ ~C. */
> if (TREE_CODE (arg0) == BIT_NOT_EXPR
> && TREE_CODE (arg1) == INTEGER_CST)
> return fold_build2_loc (loc, code, type,
> fold_convert_loc (loc, type,
> TREE_OPERAND (arg0, 0)),
> fold_build1_loc (loc, BIT_NOT_EXPR, type,
> arg1));
>
> /* Fold (X & 1) ^ 1 as (X & 1) == 0. */
> if (TREE_CODE (arg0) == BIT_AND_EXPR
> + && INTEGRAL_TYPE_P (type)
> && integer_onep (TREE_OPERAND (arg0, 1))
> && integer_onep (arg1))
> return fold_build2_loc (loc, EQ_EXPR, type, arg0,
> build_zero_cst (TREE_TYPE (arg0)));
>
> /* Fold (X & Y) ^ Y as ~X & Y. */
> if (TREE_CODE (arg0) == BIT_AND_EXPR
> && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
> {
> tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
> @@ -11487,33 +11487,35 @@ fold_binary_loc (location_t loc,
> && reorder_operands_p (arg0, TREE_OPERAND (arg1, 1)))
> return omit_one_operand_loc (loc, type, arg0, TREE_OPERAND (arg1,
> 1));
> /* X & (Y | X) is (Y, X). */
> if (TREE_CODE (arg1) == BIT_IOR_EXPR
> && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0)
> && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
> return omit_one_operand_loc (loc, type, arg0, TREE_OPERAND (arg1,
> 0));
>
> /* Fold (X ^ 1) & 1 as (X & 1) == 0. */
> if (TREE_CODE (arg0) == BIT_XOR_EXPR
> + && INTEGRAL_TYPE_P (type)
> && integer_onep (TREE_OPERAND (arg0, 1))
> && integer_onep (arg1))
> {
> tree tem2;
> tem = TREE_OPERAND (arg0, 0);
> tem2 = fold_convert_loc (loc, TREE_TYPE (tem), arg1);
> tem2 = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (tem),
> tem, tem2);
> return fold_build2_loc (loc, EQ_EXPR, type, tem2,
> build_zero_cst (TREE_TYPE (tem)));
> }
> /* Fold ~X & 1 as (X & 1) == 0. */
> if (TREE_CODE (arg0) == BIT_NOT_EXPR
> + && INTEGRAL_TYPE_P (type)
> && integer_onep (arg1))
> {
> tree tem2;
> tem = TREE_OPERAND (arg0, 0);
> tem2 = fold_convert_loc (loc, TREE_TYPE (tem), arg1);
> tem2 = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (tem),
> tem, tem2);
> return fold_build2_loc (loc, EQ_EXPR, type, tem2,
> build_zero_cst (TREE_TYPE (tem)));
> }
> Index: testsuite/gcc.dg/vec-andxor1.c
> ===================================================================
> --- testsuite/gcc.dg/vec-andxor1.c (revision 0)
> +++ testsuite/gcc.dg/vec-andxor1.c (working copy)
> @@ -0,0 +1,17 @@
> +/* { dg-do run } */
> +/* { dg-options "-O" } */
> +
> +typedef int vec __attribute__((vector_size(4*sizeof(int))));
> +
> +__attribute__((noinline,noclone))
> +void f (vec *x) {
> + *x = (*x & 1) ^ 1;
> +}
> +
> +int main() {
> + vec x = { 1, 2, 3, 4 };
> + f(&x);
> + if (x[0] != 0 || x[1] != 1)
> + __builtin_abort();
> + return 0;
> +}
> Index: tree.c
> ===================================================================
> --- tree.c (revision 215179)
> +++ tree.c (working copy)
> @@ -2162,20 +2162,35 @@ integer_onep (const_tree expr)
> for (i = 0; i < VECTOR_CST_NELTS (expr); ++i)
> if (!integer_onep (VECTOR_CST_ELT (expr, i)))
> return false;
> return true;
> }
> default:
> return false;
> }
> }
>
> +/* Return 1 if EXPR is the integer constant one. For complex and vector,
> + return 1 if every piece is the integer constant one. */
> +
> +int
> +integer_each_onep (const_tree expr)
> +{
> + STRIP_NOPS (expr);
> +
> + if (TREE_CODE (expr) == COMPLEX_CST)
> + return (integer_onep (TREE_REALPART (expr))
> + && integer_onep (TREE_IMAGPART (expr)));
> + else
> + return integer_onep (expr);
> +}
> +
> /* Return 1 if EXPR is an integer containing all 1's in as much precision
> as
> it contains, or a complex or vector whose subparts are such integers.
> */
>
> int
> integer_all_onesp (const_tree expr)
> {
> STRIP_NOPS (expr);
>
> if (TREE_CODE (expr) == COMPLEX_CST
> && integer_all_onesp (TREE_REALPART (expr))
> Index: tree.h
> ===================================================================
> --- tree.h (revision 215179)
> +++ tree.h (working copy)
> @@ -3936,20 +3936,25 @@ extern tree uniform_vector_p (const_tree
> extern vec<tree, va_gc> *ctor_to_vec (tree);
>
> /* integer_zerop (tree x) is nonzero if X is an integer constant of value
> 0. */
>
> extern int integer_zerop (const_tree);
>
> /* integer_onep (tree x) is nonzero if X is an integer constant of value 1.
> */
>
> extern int integer_onep (const_tree);
>
> +/* integer_onep (tree x) is nonzero if X is an integer constant of value 1,
> or
> + a vector or complex where each part is 1. */
> +
> +extern int integer_each_onep (const_tree);
> +
> /* integer_all_onesp (tree x) is nonzero if X is an integer constant
> all of whose significant bits are 1. */
>
> extern int integer_all_onesp (const_tree);
>
> /* integer_minus_onep (tree x) is nonzero if X is an integer constant of
> value -1. */
>
> extern int integer_minus_onep (const_tree);
>
>