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

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