From: Kyrylo Tkachov <[email protected]> For one-bit values, forward propagation can leave an inverted value and a comparison on opposite sides of a bit operation:
_1 = ~a_2; _3 = b_4 <= 0; _5 = _1 | _3; Apply De Morgan's law and invert the comparison to expose the associative operation: _3 = b_4 > 0; _5 = a_2 & _3; _6 = ~_5; Handle the corresponding AND form in the same way. Use invert_tree_comparison so that unordered floating-point behavior is preserved, and leave the expression unchanged when the comparison cannot be inverted. Require the negation and comparison to have single uses to avoid duplicating work. Restrict the simplification to scalar integral one-bit results. The focused tests pass on AArch64 and x86_64. They cover both bit operations and the unordered comparison needed for a NaN operand. On AArch64 the integer OR case changes from: cmp eor cset orr to: and cmp ccmp cset The instruction count is unchanged, but the new form avoids materializing an intermediate comparison result and exposes conditional-compare formation. This comes out of the thread at: https://gcc.gnu.org/pipermail/gcc-patches/2026-July/723788.html and this patch is needed as a prerequisite for that work. Bootstrapped and tested on aarch64-linux-gnu and x86_64-linux. gcc/ChangeLog: * match.pd: Apply De Morgan's law to a one-bit negation combined with a comparison. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/forwprop-44.c: New test. * gcc.dg/tree-ssa/forwprop-45.c: Likewise. Signed-off-by: Kyrylo Tkachov <[email protected]> --- gcc/match.pd | 20 ++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/forwprop-44.c | 25 ++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/forwprop-45.c | 29 +++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/forwprop-44.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/forwprop-45.c diff --git a/gcc/match.pd b/gcc/match.pd index d1a12c35ed3..20a1f9e79d3 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -2057,6 +2057,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) && element_precision (type) <= element_precision (TREE_TYPE (@1))) (bit_not (rop (convert @0) (convert @1)))))) +/* For one-bit values, expose an associative operation by applying De Morgan's + law and inverting the comparison: + ~X & (Y CMP Z) -> ~(X | (Y ICMP Z)) + ~X | (Y CMP Z) -> ~(X & (Y ICMP Z)) + where ICMP is the inverse of CMP. */ +(for op (bit_and bit_ior) + rop (bit_ior bit_and) + (for cmp (tcc_comparison) + icmp (inverted_tcc_comparison) + ncmp (inverted_tcc_comparison_with_nans) + (simplify + (op:c (bit_not:s @0) (cmp:s @1 @2)) + (if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1) + (with { enum tree_code ic = invert_tree_comparison + (cmp, HONOR_NANS (@1)); } + (if (ic == icmp) + (bit_not (rop @0 (icmp @1 @2))) + (if (ic == ncmp) + (bit_not (rop @0 (ncmp @1 @2)))))))))) + /* If we are XORing or adding two BIT_AND_EXPR's, both of which are and'ing with a constant, and the two constants have no bits in common, we should treat this as a BIT_IOR_EXPR since this may produce more diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-44.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-44.c new file mode 100644 index 00000000000..6cb79c742cc --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-44.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-forwprop1" } */ + +_Bool +f_ior (_Bool a, int b) +{ + _Bool na = !a; + _Bool cmp = b <= 0; + return na | cmp; +} + +_Bool +f_and (_Bool a, int b) +{ + _Bool na = !a; + _Bool cmp = b <= 0; + return na & cmp; +} + +/* The inverted comparisons expose an AND in f_ior and an OR in f_and. */ +/* { dg-final { scan-tree-dump-times " > 0;" 2 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-not " <= 0;" "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times " & " 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times " \\| " 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times " = ~" 2 "forwprop1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-45.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-45.c new file mode 100644 index 00000000000..f2dfcb0f04e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-45.c @@ -0,0 +1,29 @@ +/* { dg-do run } */ +/* { dg-require-effective-target flt_dbl_ldbl_inf_nan } */ +/* { dg-options "-O2 -fno-trapping-math -fdump-tree-forwprop1" } */ +/* { dg-additional-options "-fno-finite-math-only" } */ + +__attribute__ ((noipa)) _Bool +f_ior_nan (_Bool a, float b) +{ + _Bool na = !a; + _Bool cmp = b <= 0.0f; + return na | cmp; +} + +int +main (void) +{ + float nan = __builtin_nanf (""); + + if (f_ior_nan (1, nan) != 0 + || f_ior_nan (0, nan) != 1 + || f_ior_nan (1, -1.0f) != 1 + || f_ior_nan (1, 1.0f) != 0) + __builtin_abort (); + return 0; +} + +/* The inverse of <= is unordered greater when NaNs are honored. */ +/* { dg-final { scan-tree-dump-times " u> " 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times " = ~" 1 "forwprop1" } } */ -- 2.50.1 (Apple Git-155)
