On Fri, Jul 10, 2026 at 8:32 AM Odysseas Georgoudis <[email protected]> wrote:
>
> Hi Jeff,
>
> Sorry about that, Outlook turned the attachment into a OneDrive link. Here is
> the patch inline and also attached as plain file.
>
> On the RISC-V point, thanks, that makes sense. My intent is for the
> middle-end transform to expose the conditional negate / ABS semantics and
> leave target expansion/combine to recover the preferred form where that is
> better.
>
> From 81b2690e383b37222954225198f8895a370e45c0 Mon Sep 17 00:00:00 2001
> From: Odysseas Georgoudis <[email protected]>
> Date: Wed, 1 Jul 2026 02:43:49 +0100
> Subject: [PATCH v1] 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.
>
> Signed-off-by: Odysseas Georgoudis <[email protected]>
> ---
> gcc/match.pd | 15 ++++++
> gcc/testsuite/gcc.dg/tree-ssa/pr113894.c | 60 ++++++++++++++++++++++++
> 2 files changed, 75 insertions(+)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr113894.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index ddf3b61638c..70d7f3a8733 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -236,6 +236,13 @@ 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)))
> + (abs @0)))
Both forms invoke UB for -INT_MIN, so OK I guess. But does this not
also require !TYPE_SATURATING?
> +
> /* Following match patterns are used by the match_spaceship function to
> detect
> all possible spaceship combinations. */
> #if GIMPLE
> @@ -4793,6 +4800,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 00000000000..04aded67582
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr113894.c
> @@ -0,0 +1,60 @@
> +/* PR tree-optimization/113894 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +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)
> +{
> + return (x ^ -(int) cmp) + (int) cmp;
> +}
> +
> +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 "optimized" } } */
> +/* Sign tests should expose absolute value. */
> +/* { dg-final { scan-tree-dump-times " = ABS_EXPR" 2 "optimized" } } */
> --
> 2.43.5
>
> ________________________________
> From: Jeffrey Law <[email protected]>
> Sent: 10 July 2026 02:21
> To: Odysseas Georgoudis <[email protected]>; [email protected]
> <[email protected]>
> Cc: Andrew Pinski <[email protected]>
> Subject: Re: [PATCH] match.pd: Recognize branchless conditional negate
> [PR113894]
>
>
>
> On 6/30/2026 8:07 PM, Odysseas Georgoudis wrote:
> > 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.
> >
> > I could not comment on the PR because my GCC Bugzilla account is still
> > pending, so I am sending the patch here.
> >
> > Bootstrapped on x86_64-pc-linux-gnu. Tested with
> > gcc.dg/tree-ssa/tree-ssa.exp and the new gcc.dg/tree-ssa/pr113894.c
> > testcase.
> >
> > I do not have commit access.
> >
> > pr113894.patch
> > <https://1drv.ms/u/c/5a41b3fa58bb8071/IQAXsKqhUTaaQb_gOXEu4L8RAXgQUmxYo5d_eBzRtnqcKSI>
> Can you include the patch in your message. It looks like the link goes
> to onedrive and I suspect many folks aren't going to want to do that.
>
> Interestingly enough the (x ^ -cmp) + cmp form is probably optimal on
> RISC-V, so hopefully even after your match.pd change we'll still be able
> to recover optimal form across different designs.
>
> jeff
>