On Tue, Sep 29, 2026 at 10:31 AM Dominic P <[email protected]> wrote:
>
> r17-4378 folds minmax (a - c, b) + c to minmax (a, b + c) when b + c
> cannot overflow.  The fold also needs a - c not to wrap: for unsigned
> a = 0, b = 0, c = 1, MIN (a - c, b) + c is 1 but MIN (a, b + c) is 0,
> and the MAX form gives 0 against 1.  Require that with
> gimple_match_no_overflow_p.  The std::vector::push_back case from the
> PR, where a is 2147483647, still folds.
>
> Bootstrapped and regression tested on x86_64-pc-linux-gnu, and dg.exp,
> tree-ssa.exp and execute.exp on aarch64-linux-gnu under qemu.
>
> Assisted-by: Claude Opus 5 (Anthropic)
>
>         PR tree-optimization/127103
>
> gcc/ChangeLog:
>
>         * match.pd (minmax (a - c, b) + c): Also require that a - c
>         does not overflow.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/torture/pr127103.c: New test.
>
> Signed-off-by: Dominic P <[email protected]>
> ---
> OK for trunk?
>
> Vector types are unaffected: without ranges for them the rule never fires,
> before or after the patch.
>
>  gcc/match.pd                            |  3 ++-
>  gcc/testsuite/gcc.dg/torture/pr127103.c | 33 +++++++++++++++++++++++++
>  2 files changed, 35 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr127103.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index c70a8e6d6d2..33a573cfcb2 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -531,12 +531,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>     (if (gimple_match_range_of_expr (vr0, @0, @2)
>         && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr0))
>      (max (plus @0 @0) @1)))))
> -/* minmax (a - c, b) + c -> minmax (a, b + c) if b+c don't overflow.  */
> +/* minmax (a - c, b) + c -> minmax (a, b + c) if a-c and b+c don't overflow. 
>  */
>  (for minmax (min max)
>   (simplify
>    (plus:c @0 (minmax:cs@3 (minus @1 @0) @2))
>    (with { int_range_max vr0, vr2; }
>     (if (TYPE_UNSIGNED (type)
> +       && gimple_match_no_overflow_p (MINUS_EXPR, type, @1, @0, @3)
>         && gimple_match_range_of_expr (vr0, @0)
>         && gimple_match_range_of_expr (vr2, @2, @3)
>         && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr2))

Since we already get the range of @0 here, can you expand out the call
to gimple_match_no_overflow_p instead?
So it should just be adding:
&& gimple_match_range_of_expr (vr1, @1, @3)
&& range_op_handler (MINUS_EXPR).overflow_free_p (vr1, vr0)



> diff --git a/gcc/testsuite/gcc.dg/torture/pr127103.c 
> b/gcc/testsuite/gcc.dg/torture/pr127103.c
> new file mode 100644
> index 00000000000..3b622d3388f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/pr127103.c
> @@ -0,0 +1,33 @@
> +/* { dg-do run } */
> +/* minmax (a - c, b) + c must not become minmax (a, b + c) when a - c
> +   can wrap.  */
> +
> +__attribute__((noipa)) unsigned
> +f_min (unsigned a, unsigned b, unsigned c)
> +{
> +  c &= 1;
> +  b &= 1;
> +  unsigned t = a - c;
> +  t = t < b ? t : b;
> +  return t + c;
> +}
> +
> +__attribute__((noipa)) unsigned
> +f_max (unsigned a, unsigned b, unsigned c)
> +{
> +  c &= 1;
> +  b &= 1;
> +  unsigned t = a - c;
> +  t = t > b ? t : b;
> +  return t + c;
> +}
> +
> +int
> +main (void)
> +{
> +  if (f_min (0, 0, 1) != 1)
> +    __builtin_abort ();
> +  if (f_max (0, 0, 1) != 0)
> +    __builtin_abort ();
> +  return 0;
> +}
> --
> 2.55.0
>

Reply via email to