On Wed, Jul 22, 2026 at 6:14 AM <[email protected]> wrote:
>
> From: Kyrylo Tkachov <[email protected]>
>
> The existing zero-one conditional rules fold A ? B : 0 to A & B.
> They do not handle a negated Boolean arm, so these forms can retain a
> diamond:
>
>   A ? -B : 0
>   A ? -B : -1
>
> For GIMPLE condition A and zero-one B, fold them to:
>
>   -(A & B)
>   -((A ^ 1) | B)
>
> Keep the rules in the GIMPLE-only group before the related zero-one
> conditional folds.
> On AArch64, the conditional branch
> and fallback return in each direct form become a CMP, CCMP and CSETM sequence.
>
> Bootstrapped and tested on aarch64-none-linux-gnu and x86_64-linux.
> As discussed, this is a prerequisite transformation needed to avoid
> regressions from:
> https://gcc.gnu.org/pipermail/gcc-patches/2026-July/723788.html

I was thinking about this some more.
Can we do the following instead?
Can we factor out the negative from the phi instead?

That is if we have:
```
if (a)
{
  b = cmp;
  c = (convert)b;
  d = -c;
}
else
  d = [0,-1];

into:
```
if (a)
{
  b = cmp;
  c = (convert)b;
}
else
 c = [0,1];
d = -c;
```
Which then will factor into:
```
if (a)
    b = cmp;
else
   b = [0,1];
c = (convert)b;
d = -c;
```

That is the what negative expression is coming from should be a
convert from a boolean type and doing it then?
It should go under:
```
      /* TODO: handle more than just casts here. */
      if (!gimple_assign_cast_p (arg0_def_stmt))
       return false;
```

The reason why I am asking to do it this way is that this will allow
https://gcc.gnu.org/pipermail/gcc-patches/2026-July/724889.html to
work without adding another case for 0/-1 too.

We might want to add support for BIT_NOT_EXPR for boolean types too
but that is for another patch.

Thanks,
Andrea



>
> gcc/ChangeLog:
>
>         * match.pd: Fold conditional negative zero-one values to negated
>         bitwise operations.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/tree-ssa/phiopt-neg-bool-mask-1.c: New test.
>         * gcc.dg/tree-ssa/phiopt-neg-bool-mask-2.c: Likewise.
>
> Signed-off-by: Kyrylo Tkachov <[email protected]>
> ---
>  gcc/match.pd                                  | 11 ++++++
>  .../gcc.dg/tree-ssa/phiopt-neg-bool-mask-1.c  | 36 +++++++++++++++++++
>  .../gcc.dg/tree-ssa/phiopt-neg-bool-mask-2.c  | 36 +++++++++++++++++++
>  3 files changed, 83 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phiopt-neg-bool-mask-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phiopt-neg-bool-mask-2.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index 9d4ab622fe5..16954fabe2d 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -6975,6 +6975,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>     (convert (min (convert:utype @0) (convert:utype @1))))))
>
>  #if GIMPLE
> +/* For condition A and zero-one B, A ? -B : 0 -> -(A & B).  */
> +(simplify
> + (cond @0 (negate:s zero_one_valued_p@1) integer_zerop)
> + (negate (bit_and (convert @0) @1)))
> +
> +/* For condition A and zero-one B, A ? -B : -1 -> -((A ^ 1) | B).  */
> +(simplify
> + (cond @0 (negate:s zero_one_valued_p@1) integer_all_onesp)
> + (negate (bit_ior (bit_xor (convert @0)
> +                          { build_one_cst (type); }) @1)))
> +
>  /* These patterns should be after min/max detection as simplifications
>     of `(type)(zero_one ==/!= 0)` to `(type)(zero_one)`
>     and `(type)(zero_one^1)` are not done yet.  See PR 110637.
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phiopt-neg-bool-mask-1.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/phiopt-neg-bool-mask-1.c
> new file mode 100644
> index 00000000000..a9313f4c6f7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/phiopt-neg-bool-mask-1.c
> @@ -0,0 +1,36 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-phiopt2" } */
> +
> +int
> +direct_negative_mask (int outer, int value)
> +{
> +  int mask = -(value > 0);
> +  return outer > 0 ? mask : 0;
> +}
> +
> +int
> +direct_negative_mask_minus_one (int outer, int value)
> +{
> +  int mask = -(value > 0);
> +  return outer > 0 ? mask : -1;
> +}
> +
> +unsigned int
> +direct_negative_mask_unsigned (int outer, int value)
> +{
> +  unsigned int mask = -(unsigned int) (value > 0);
> +  return outer > 0 ? mask : 0;
> +}
> +
> +unsigned int
> +direct_negative_mask_minus_one_unsigned (int outer, int value)
> +{
> +  unsigned int mask = -(unsigned int) (value > 0);
> +  return outer > 0 ? mask : -1U;
> +}
> +
> +/* The zero else arms contribute two AND operations.  */
> +/* { dg-final { scan-tree-dump-times " & " 2 "phiopt2" } } */
> +/* The minus-one else arms contribute two OR operations.  */
> +/* { dg-final { scan-tree-dump-times " \\| " 2 "phiopt2" } } */
> +/* { dg-final { scan-tree-dump-not "if \\(" "phiopt2" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phiopt-neg-bool-mask-2.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/phiopt-neg-bool-mask-2.c
> new file mode 100644
> index 00000000000..421d31de6ec
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/phiopt-neg-bool-mask-2.c
> @@ -0,0 +1,36 @@
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fgimple" } */
> +
> +/* Do not use an arbitrary negated operand as a numeric zero-one value in the
> +   mask identities.  */
> +
> +__attribute__ ((noipa)) int __GIMPLE ()
> +zero_else_non_boolean_value (_Bool c, int b)
> +{
> +  int nb;
> +  int r;
> +
> +  nb = -b_2(D);
> +  r = c_1(D) ? nb : 0;
> +  return r;
> +}
> +
> +__attribute__ ((noipa)) int __GIMPLE ()
> +minus_one_else_non_boolean_value (_Bool c, int b)
> +{
> +  int nb;
> +  int r;
> +
> +  nb = -b_2(D);
> +  r = c_1(D) ? nb : _Literal (int) -1;
> +  return r;
> +}
> +
> +int
> +main (void)
> +{
> +  if (zero_else_non_boolean_value (1, 2) != -2
> +      || minus_one_else_non_boolean_value (0, 2) != -1)
> +    __builtin_abort ();
> +  return 0;
> +}
> --
> 2.50.1 (Apple Git-155)
>

Reply via email to