On Fri, Mar 13, 2026 at 10:43 PM Philipp Tomsich
<[email protected]> wrote:
>
> The single_use restriction on the X +- C1 CMP C2 -> X CMP C2 -+ C1
> simplification (for eq/ne) prevents folding patterns like (++*a == 1)
> into (*a == 0) when the defining SSA value has multiple uses.
>
> Comparing against zero is cheaper on most targets (beqz on RISC-V,
> cbz on AArch64), so the transform is profitable even when the
> defining SSA has multiple uses.  Relax single_use when the folded
> comparison constant is zero.
>
> For example, given:
>   _1 = *a;
>   _2 = _1 + 1;
>   *a = _2;
>   if (_2 == 1)
>
> match.pd now produces:
>   if (_1 == 0)
>
> which generates beqz/cbz instead of li+beq/cmp+b.eq.
>
> This is a partial fix towards the issue described in PR120283.

One reason for the single-use check is that we want to avoid the
transform for a loop exit check where the result prevents coalescing
of the in-loop IV before/after update and thus requires a non-empty
latch block.  IIRC there's code that tries to
fixup during out-of-SSA, but please double-check this actually works
(you still get a copy then, of course).

That said, the check was added on purpose.

Richard.

>
> gcc/ChangeLog:
>
>         * match.pd: Relax single_use for eq/ne when folded constant
>         is zero.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/tree-ssa/forwprop-pre-incr-cmp.c: New test.
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index 7f16fd4e0814..c8601ea6878a 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -9864,7 +9864,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>       (if (TREE_OVERFLOW (res)
>           && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
>        { constant_boolean_node (cmp == NE_EXPR, type); }
> -      (if (single_use (@3))
> +      (if (single_use (@3) || wi::to_wide (res) == 0)
>         (cmp @0 { TREE_OVERFLOW (res)
>                  ? drop_tree_overflow (res) : res; }))))))))
>  (for cmp (lt le gt ge)
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-pre-incr-cmp.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-pre-incr-cmp.c
> new file mode 100644
> index 000000000000..cfa6afe304c9
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-pre-incr-cmp.c
> @@ -0,0 +1,33 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-forwprop2" } */
> +
> +/* Verify that the X +- C1 CMP C2 -> X CMP C2 -+ C1 pattern fires
> +   when the folded constant is zero, even without single use.
> +   PR tree-optimization/120283.  */
> +
> +void g ();
> +
> +/* Unsigned EQ: ++*a == 1 -> *a == 0.  */
> +void f1 (unsigned int *a)
> +{
> +  if (++*a == 1)
> +    g ();
> +}
> +
> +/* Unsigned NE: ++*a != 1 -> *a != 0.  */
> +void f2 (unsigned int *a)
> +{
> +  if (++*a != 1)
> +    g ();
> +}
> +
> +/* Unsigned EQ with addend > 1: (*a += 3) == 3 -> *a == 0.  */
> +void f3 (unsigned int *a)
> +{
> +  if ((*a += 3) == 3)
> +    g ();
> +}
> +
> +/* Positive: f1, f3 should fold to == 0, f2 should fold to != 0.  */
> +/* { dg-final { scan-tree-dump-times "== 0" 2 "forwprop2" } } */
> +/* { dg-final { scan-tree-dump-times "!= 0" 1 "forwprop2" } } */
> --
> 2.34.1
>

Reply via email to