[gcc r17-2360] match.pd: Recognize branchless conditional negate [PR113894]

Jeff Law via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:01d1d20266a4c1f02457dd9df1b25a733d701466

commit r17-2360-g01d1d20266a4c1f02457dd9df1b25a733d701466
Author: Odysseas Georgoudis <[email protected]>
Date:   Mon Jul 13 10:09:10 2026 -0600

    match.pd: Recognize branchless conditional negate [PR113894]
    
    This patch teaches match.pd to recognize the branchless conditional negate
    idiom (x ^ -cmp) + cmp when cmp is known to be zero or one.  The
    expression is folded to a conditional negate form.
    
    For the sign-test spelling based on x < 0, the patch exposes ABS_EXPR.
    
            PR tree-optimization/113894
    
    gcc/ChangeLog:
    
            * match.pd: Add simplifications for branchless conditional negate
            and sign-test absolute value idioms.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/pr113894.c: New test.

Diff:
---
 gcc/match.pd                             | 17 +++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr113894.c | 63 ++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+)

diff --git a/gcc/match.pd b/gcc/match.pd
index 9d4ab622fe57..d1a12c35ed36 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -236,6 +236,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       && !TYPE_UNSIGNED (TREE_TYPE (@0)))
   (abs @0)))
 
+/* (X ^ -(X < 0)) + (X < 0) -> abs (X) */
+(simplify
+ (plus:c (bit_xor:c @0 (negate (convert@1 (lt @0 integer_zerop)))) @1)
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+      && !TYPE_UNSIGNED (TREE_TYPE (@0))
+      && !TYPE_SATURATING (TREE_TYPE (@0))
+      && (GIMPLE || !TREE_SIDE_EFFECTS (@0)))
+  (abs @0)))
+
 /* Following match patterns are used by the match_spaceship function to detect
    all possible spaceship combinations.  */
 #if GIMPLE
@@ -4853,6 +4862,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       && (GIMPLE || !TREE_SIDE_EFFECTS (@1)))
   (cond (convert:boolean_type_node @2) @1 @0)))
 
+/* Transform (A ^ -cmp) + cmp into cmp ? -A : A.  */
+(simplify
+ (plus:c (bit_xor:c @0 (negate zero_one_valued_p@1)) @1)
+ (if (INTEGRAL_TYPE_P (type)
+      && !TYPE_SATURATING (type)
+      && (GIMPLE || !TREE_SIDE_EFFECTS (@0)))
+  (cond (convert:boolean_type_node @1) (negate @0) @0)))
+
 /* Transform A & (B*cmp) into (A&B)*cmp.  */
 (simplify
  (bit_and:c (mult:cs zero_one_valued_p@0 @1) @2)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr113894.c b/gcc/testsuite/gcc.dg/tree-ssa/pr113894.c
new file mode 100644
index 000000000000..dc7a450d3e8d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr113894.c
@@ -0,0 +1,63 @@
+/* PR tree-optimization/113894 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-forwprop1" } */
+
+int f_cmp_lt(int x, int y)
+{
+  int cmp = x < y;
+  return (x ^ -cmp) + cmp;
+}
+
+int f_cmp_gt_commuted(int x, int y)
+{
+  int cmp = x > y;
+  return cmp + (-cmp ^ x);
+}
+
+unsigned f_unsigned_cmp(unsigned x, unsigned y)
+{
+  unsigned cmp = x < y;
+  return (x ^ -cmp) + cmp;
+}
+
+int f_mask(int x, unsigned y)
+{
+  int cmp = y & 1;
+  return (x ^ -cmp) + cmp;
+}
+
+int f_bool(int x, _Bool cmp)
+{
+  int icmp = cmp;
+  return (x ^ -icmp) + icmp;
+}
+
+int f_abs_int(int x)
+{
+  int cmp = x < 0;
+  return (x ^ -cmp) + cmp;
+}
+
+long f_abs_long(long x)
+{
+  long cmp = x < 0;
+  return (x ^ -cmp) + cmp;
+}
+
+int f_signed_not_zero_one(int x, int cmp)
+{
+  return (x ^ -cmp) + cmp;
+}
+
+unsigned f_unsigned_not_zero_one(unsigned x, unsigned cmp)
+{
+  return (x ^ -cmp) + cmp;
+}
+
+/* The branchless conditional negate spelling should only survive when cmp is
+   not known to be 0 or 1.  */
+/* { dg-final { scan-tree-dump-times " \\^ " 2 "forwprop1" } } */
+/* Sign tests should expose absolute value.  */
+/* { dg-final { scan-tree-dump-times " = ABS_EXPR" 2 "forwprop1" } } */
+/* Other zero-one predicates should expose conditional negation.  */
+/* { dg-final { scan-tree-dump-times " \\? " 5 "forwprop1" } } */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.