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)
