On Mon, 12 May 2025, Icen Zeyada wrote:

>     Generalize existing scalar gimple_fold rules to apply the same
>     bitwise comparison simplifications to vector types.  Previously, an
>     expression like
> 
>         (x < y) && (x > y)
> 
>     would fold to `false` if x and y are scalars, but equivalent vector
>     comparisons were left untouched.  This patch enables folding of
>     patterns of the form
> 
>         (cmp x y) bit_and (cmp x y)
>         (cmp x y) bit_ior (cmp x y)
> 
>     for vector operands as well, ensuring consistent optimization across
>     all data types.
> 
>     PR tree-optimization/119196
> 
>     gcc/ChangeLog:
> 
>       * match.pd: Allow scalar optimizations with bitwise AND/OR to apply to 
> vectors.
> 
>     gcc/testsuite/ChangeLog:
> 
>       * gcc.target/aarch64/vector-compare-5.c: Add new test for vector 
> compare simplification.
> 
> Signed-off-by: Icen Zeyada <icen.zeya...@arm.com>
> ---
>  gcc/match.pd                                  | 19 +++++++--
>  .../gcc.target/aarch64/vector-compare-5.c     | 41 +++++++++++++++++++
>  2 files changed, 56 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/aarch64/vector-compare-5.c
> 
> diff --git a/gcc/match.pd b/gcc/match.pd
> index ab496d923cc0..a8a2e01e5e64 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -3620,7 +3620,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>     (bit_and:c (code1:c@3 @0 @1) (code2:c@4 (convert?@c0 @0) @2))
>     (if ((TREE_CODE (@1) == INTEGER_CST
>        && TREE_CODE (@2) == INTEGER_CST)
> -     || ((INTEGRAL_TYPE_P (TREE_TYPE (@1))
> +     || ((ANY_INTEGRAL_TYPE_P (TREE_TYPE (@1))
>            || POINTER_TYPE_P (TREE_TYPE (@1)))
>           && bitwise_equal_p (@1, @2)))
>      (with
> @@ -3697,7 +3697,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>    (bit_and (code1:c@3 @0 @1) (code2:c@4 @0 @2))
>    (if ((TREE_CODE (@1) == INTEGER_CST
>       && TREE_CODE (@2) == INTEGER_CST)
> -       || ((INTEGRAL_TYPE_P (TREE_TYPE (@1))
> +       || ((ANY_INTEGRAL_TYPE_P (TREE_TYPE (@1))
>           || POINTER_TYPE_P (TREE_TYPE (@1)))
>          && operand_equal_p (@1, @2)))
>     (with
> @@ -3747,7 +3747,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>     (bit_ior:c (code1:c@3 @0 @1) (code2:c@4 (convert?@c0 @0) @2))
>     (if ((TREE_CODE (@1) == INTEGER_CST
>        && TREE_CODE (@2) == INTEGER_CST)
> -     || ((INTEGRAL_TYPE_P (TREE_TYPE (@1))
> +     || ((ANY_INTEGRAL_TYPE_P (TREE_TYPE (@1))
>           || POINTER_TYPE_P (TREE_TYPE (@1)))
>           && bitwise_equal_p (@1, @2)))
>      (with
> @@ -3880,7 +3880,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>       rcmp (eq gt le eq ge lt)
>   (simplify
>    (eq:c (cmp1:c @0 @1) (cmp2 @0 @1))
> -  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0)))
> +  (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
> +             || POINTER_TYPE_P (TREE_TYPE (@0)))
>      (rcmp @0 @1))))

For all of the above you need to ensure that we can 
expand the vector comparison via expand_vec_cmp_expr_p.

>  /* (type)([0,1]@a != 0) -> (type)a
> @@ -6510,6 +6511,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>               { build_int_cst (integer_type_node, prec - 1);}))))))
>  #endif
>  
> +(for op1 (simple_comparison)
> + (for op2 (simple_comparison)
> +  (for lop (bit_and bit_ior)
> +    (simplify
> +       (lop
> +        (vec_cond (op1 @0 @1) integer_minus_onep@2 integer_zerop@3)
> +        (vec_cond (op2 @0 @1) integer_minus_onep@2 integer_zerop@3))
> +       (with { tree op_type = truth_type_for (TREE_TYPE (@0)); }
> +             (vec_cond (lop:op_type (op1 @0 @1) (op2 @0 @1)) @2 @3))))))
> +

Likewise here, also for the vec_cond via expand_vec_cond_expr_p.  Why
do you compute a "new" op_type here and not re-use that of the
(op1 @0 @1) compares and the compares themselves?  I'd have expected

> +    (simplify
> +       (lop
> +        (vec_cond (op1@00 @0 @1) integer_minus_onep@2 integer_zerop@3) 
> +        (vec_cond (op2@01 @0 @1) integer_minus_onep@2 integer_zerop@3))
          (vec_cond (lop @00 @01) @2 @3)

and why match a comparison at all? Why not

    (simplify
      (lop
       (vec_cond @0 integer_minus_onep@2 integer_zerop@3)
       (vec_cond @1 @2 @3))
      (vec_cond (lop @0 @1) @2 @3))

?

IMO this pattern should be in a separate patch.

>  (for cnd (cond vec_cond)
>   /* (a != b) ? (a - b) : 0 -> (a - b) */
>   (simplify
> diff --git a/gcc/testsuite/gcc.target/aarch64/vector-compare-5.c 
> b/gcc/testsuite/gcc.target/aarch64/vector-compare-5.c
> new file mode 100644
> index 000000000000..c4b95a21996d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/vector-compare-5.c
> @@ -0,0 +1,41 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +/* { dg-additional-options "-fdump-tree-original-all" } */
> +
> +typedef int v4i __attribute__((vector_size(4*sizeof(int))));
> +
> +/* Ensure we can simplify `VEC_COND_EXPR(a OP1 b) OP2 VEC_COND_EXPR(a OP3 b)`
> + * into `VEC_COND_EXPR(a OP4 b)`
> + */
> +
> +void use (v4i const *z);
> +
> +void
> +g (v4i *x, v4i const *y, v4i *z, v4i *t)
> +{
> +  *z = *x > *y | *x == *y; // expect >=
> +  *t = *x > *y | *x <= *y; // expect true
> +}
> +
> +void
> +h (v4i *x, v4i const *y, v4i *z, v4i *t)
> +{
> +  *z = *x <= *y & *x >= *y; // expect x == y
> +  *t = *x <= *y & *x != *y; // expect x<y
> +}
> +
> +void
> +i (v4i *x, v4i const *y, v4i *z, v4i *t)
> +{
> +  *z = *x == *y | *x != *y; // expect true
> +  *t = *x == *y & *x != *y; // expect false
> +}
> +
> +/* { dg-final { scan-tree-dump 
> ".*\\*zD\\.\\d+\\s*=\\s*VEC_COND_EXPR\\s*<\\s*\\*xD\\.\\d+\\s*>=\\s*VIEW_CONVERT_EXPR<v4iD\\.\\d+>\\(\\*yD\\.\\d+\\)\\s*,\\s*\\{\\s*-1(,\\s*-1){3}\\s*\\}\\s*,\\s*\\{\\s*0(,\\s*0){3}\\s*\\}\\s*>\\s*;"
>  "original" } } */
> +/* { dg-final { scan-tree-dump 
> ".*\\*tD\\.\\d+\\s*=\\s*\\{\\s*-1(,\\s*-1){3}\\s*\\}\\s*;" "original" } } */
> +/* { dg-final { scan-tree-dump 
> ".*\\*zD\\.\\d+\\s*=\\s*VEC_COND_EXPR\\s*<\\s*\\*xD\\.\\d+\\s*==\\s*VIEW_CONVERT_EXPR<v4iD\\.\\d+>\\(\\*yD\\.\\d+\\)\\s*,\\s*\\{\\s*-1(,\\s*-1){3}\\s*\\}\\s*,\\s*\\{\\s*0(,\\s*0){3}\\s*\\}\\s*>\\s*;"
>  "original" } } */
> +/* { dg-final { scan-tree-dump 
> ".*\\*tD\\.\\d+\\s*=\\s*VEC_COND_EXPR\\s*<\\s*\\*xD\\.\\d+\\s*<\\s*VIEW_CONVERT_EXPR<v4iD\\.\\d+>\\(\\*yD\\.\\d+\\)\\s*,\\s*\\{\\s*-1(,\\s*-1){3}\\s*\\}\\s*,\\s*\\{\\s*0(,\\s*0){3}\\s*\\}\\s*>\\s*;"
>  "original" } } */
> +/* { dg-final { scan-tree-dump 
> ".*\\*zD\\.\\d+\\s*=\\s*\\{\\s*-1(,\\s*-1){3}\\s*\\}\\s*;" "original" } } */
> +/* { dg-final { scan-tree-dump 
> ".*\\*tD\\.\\d+\\s*=\\s*\\{\\s*0(,\\s*0){3}\\s*\\}\\s*;" "original" } } */
> +
> +
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to