On Tue, Jul 14, 2026 at 10:02 AM Naveen
<[email protected]> wrote:
>
> PR tree-optimization/98602 shows that vector conditional min/max
> expressions can be missed after comparison canonicalization. For
> example,
>
> X > -100 ? X : -100
> is canonicalized to
> X >= -99 ? X : -100.
>
> The existing VEC_COND_EXPR min/max patterns require the comparison and
> result constants to be equal, so they do not recognize the canonicalized
> off-by-one form.
>
> Add patterns for the GE/LT forms produced from negative signed maximum
> expressions and for the LE/GT forms produced from positive signed or
> unsigned minimum expressions. Handle both normal and reversed
> conditional arms.
The PR talks about this in context of folding to min/max, but I'm not exactly
seeing why this requires uniform vectors, doesn't the same issue exist for
X >= { -99, -98 } ? X : { -100, -99 }?
I'll note that while canonialization is good, for vectors we'd like to see
as many equal vector constants instead. That might even be true
for scalar constants on most risc archs, at least for those large enough
to require separate materialization instructions.
Richard.
>
> gcc/ChangeLog:
> PR tree-optimization/98602
> * match.pd (vec_cond (ge @0 INTEGER_CST) @0 INTEGER_CST):
> New simplification.
> (vec_cond (lt @0 INTEGER_CST) INTEGER_CST @0): Likewise.
> (vec_cond (le @0 INTEGER_CST) @0 INTEGER_CST): Likewise.
> (vec_cond (gt @0 INTEGER_CST) INTEGER_CST @0): Likewise.
>
> gcc/testsuite/ChangeLog:
> PR tree-optimization/98602
> * g++.target/aarch64/sve/max_1.C: Remove fixed XFAILs.
> * g++.target/aarch64/sve/min_1.C: Likewise.
>
> Signed-off-by: Naveen <[email protected]>
> ---
> gcc/match.pd | 59 ++++++++++++++++++++
> gcc/testsuite/g++.target/aarch64/sve/max_1.C | 10 ++--
> gcc/testsuite/g++.target/aarch64/sve/min_1.C | 44 +++++++--------
> 3 files changed, 86 insertions(+), 27 deletions(-)
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index d1a12c35ed3..9832b821173 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -6818,6 +6818,65 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> && target_supports_op_p (type, MINMAX, optab_vector))
> (minmax @0 @1))))
>
> +/* Comparison canonicalization changes X > C to X >= C + 1 for
> + negative C and X < C to X <= C - 1 for positive C. Handle the
> + resulting off-by-one constants here. */
> +(simplify
> + (vec_cond (ge @0 uniform_integer_cst_p@1) @0 uniform_integer_cst_p@2)
> + (with {
> + tree cmp_cst = uniform_integer_cst_p (@1);
> + tree res_cst = uniform_integer_cst_p (@2);
> + }
> + (if (VECTOR_INTEGER_TYPE_P (type)
> + && target_supports_op_p (type, MAX_EXPR, optab_vector)
> + && tree_int_cst_sgn (res_cst) == -1
> + && wi::eq_p (wi::to_wide (cmp_cst),
> + wi::to_wide (res_cst) + 1))
> + (max @0 @2))))
> +
> +/* Also handle the equivalent maximum form with the conditional arms
> + reversed and the comparison inverted. */
> +(simplify
> + (vec_cond (lt @0 uniform_integer_cst_p@1) uniform_integer_cst_p@2 @0)
> + (with {
> + tree cmp_cst = uniform_integer_cst_p (@1);
> + tree res_cst = uniform_integer_cst_p (@2);
> + }
> + (if (VECTOR_INTEGER_TYPE_P (type)
> + && target_supports_op_p (type, MAX_EXPR, optab_vector)
> + && tree_int_cst_sgn (res_cst) == -1
> + && wi::eq_p (wi::to_wide (cmp_cst),
> + wi::to_wide (res_cst) + 1))
> + (max @0 @2))))
> +
> +(simplify
> + (vec_cond (le @0 uniform_integer_cst_p@1) @0 uniform_integer_cst_p@2)
> + (with {
> + tree cmp_cst = uniform_integer_cst_p (@1);
> + tree res_cst = uniform_integer_cst_p (@2);
> + }
> + (if (VECTOR_INTEGER_TYPE_P (type)
> + && target_supports_op_p (type, MIN_EXPR, optab_vector)
> + && tree_int_cst_sgn (res_cst) == 1
> + && wi::eq_p (wi::to_wide (cmp_cst),
> + wi::to_wide (res_cst) - 1))
> + (min @0 @2))))
> +
> +/* Also handle the equivalent minimum form with the conditional arms
> + reversed and the comparison inverted. */
> +(simplify
> + (vec_cond (gt @0 uniform_integer_cst_p@1) uniform_integer_cst_p@2 @0)
> + (with {
> + tree cmp_cst = uniform_integer_cst_p (@1);
> + tree res_cst = uniform_integer_cst_p (@2);
> + }
> + (if (VECTOR_INTEGER_TYPE_P (type)
> + && target_supports_op_p (type, MIN_EXPR, optab_vector)
> + && tree_int_cst_sgn (res_cst) == 1
> + && wi::eq_p (wi::to_wide (cmp_cst),
> + wi::to_wide (res_cst) - 1))
> + (min @0 @2))))
> +
> /* Try to optimize x < 0 ? -1 : 0 into (signed) x >> 31
> and x < 0 ? 1 : 0 into (unsigned) x >> 31. */
> (simplify
> diff --git a/gcc/testsuite/g++.target/aarch64/sve/max_1.C
> b/gcc/testsuite/g++.target/aarch64/sve/max_1.C
> index caf9d7cd9bb..6328d5a1b38 100644
> --- a/gcc/testsuite/g++.target/aarch64/sve/max_1.C
> +++ b/gcc/testsuite/g++.target/aarch64/sve/max_1.C
> @@ -39,11 +39,11 @@ TEST_TYPE (uint32_t, 128, 7, 255)
> /* { dg-final { scan-assembler-times {\tumax\tz[0-9]+\.h, p[0-7]/m,
> z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
> /* { dg-final { scan-assembler-times {\tumax\tz[0-9]+\.s, p[0-7]/m,
> z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
>
> -/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b,
> #-100\n} 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b,
> #-110\n} 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b,
> #-120\n} 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.h, z[0-9]+\.h,
> #-128\n} 2 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.s, z[0-9]+\.s,
> #-128\n} 1 { xfail *-*-* } } } */
> +/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b,
> #-100\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b,
> #-110\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b,
> #-120\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.h, z[0-9]+\.h,
> #-128\n} 2 } } */
> +/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.s, z[0-9]+\.s,
> #-128\n} 1 } } */
>
> /* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b, #50\n}
> 3 } } */
> /* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.h, z[0-9]+\.h, #50\n}
> 2 } } */
> diff --git a/gcc/testsuite/g++.target/aarch64/sve/min_1.C
> b/gcc/testsuite/g++.target/aarch64/sve/min_1.C
> index 9c84690cd1b..172fa6a9da5 100644
> --- a/gcc/testsuite/g++.target/aarch64/sve/min_1.C
> +++ b/gcc/testsuite/g++.target/aarch64/sve/min_1.C
> @@ -45,29 +45,29 @@ TEST_TYPE (uint32_t, 128, 7, 255)
> /* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.h, z[0-9]+\.h,
> #-128\n} 2 } } */
> /* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.s, z[0-9]+\.s,
> #-128\n} 1 } } */
>
> -/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b, #50\n}
> 3 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.h, z[0-9]+\.h, #50\n}
> 2 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.s, z[0-9]+\.s, #50\n}
> 1 { xfail *-*-* } } } */
> +/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b, #50\n}
> 3 } } */
> +/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.h, z[0-9]+\.h, #50\n}
> 2 } } */
> +/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.s, z[0-9]+\.s, #50\n}
> 1 } } */
>
> -/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b,
> #100\n} 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b,
> #110\n} 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b,
> #120\n} 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.h, z[0-9]+\.h,
> #127\n} 2 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.s, z[0-9]+\.s,
> #127\n} 1 { xfail *-*-* } } } */
> +/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b,
> #100\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b,
> #110\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b,
> #120\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.h, z[0-9]+\.h,
> #127\n} 2 } } */
> +/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.s, z[0-9]+\.s,
> #127\n} 1 } } */
>
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #2\n}
> 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #3\n}
> 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #4\n}
> 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #5\n}
> 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #6\n}
> 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s, #7\n}
> 1 { xfail *-*-* } } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #2\n}
> 1 } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #3\n}
> 1 } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #4\n}
> 1 } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #5\n}
> 1 } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #6\n}
> 1 } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s, #7\n}
> 1 } } */
>
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #50\n}
> 3 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #50\n}
> 2 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s, #50\n}
> 1 { xfail *-*-* } } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #50\n}
> 3 } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #50\n}
> 2 } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s, #50\n}
> 1 } } */
>
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b,
> #250\n} 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b,
> #251\n} 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b,
> #253\n} 1 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h,
> #255\n} 2 { xfail *-*-* } } } */
> -/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s,
> #255\n} 1 { xfail *-*-* } } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b,
> #250\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b,
> #251\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b,
> #253\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h,
> #255\n} 2 } } */
> +/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s,
> #255\n} 1 } } */
> --
> 2.34.1
>