On Tue, Jan 6, 2026 at 1:46 PM Daniel Barboza
<[email protected]> wrote:
>
> Add a transformation for a nested lshift/rshift inside a plus that compares 
> for
> equality with the same operand of the plus. In other words:
>
> ((a OP b) + c EQ|NE c) ? x : y
>
> becomes, for OP = (lshift, rshift) and in a scenario without overflows:
>
> a !=/== 0 ? x : y

I think we want the transformation even if it is used outside of a cond_expr.
Also the above is valid even for types that wrap; just not valid for
types that trap on overflow.

As we already have a pattern for `a + C == C`:
```
/* For equality, this is also true with wrapping overflow.  */
(for op (eq ne)
 (simplify
  (op:c (nop_convert?@3 (plus:c@2 @0 (convert1? @1))) (convert2? @1))
  (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
       && (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
           || TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
       && (CONSTANT_CLASS_P (@0) || (single_use (@2) && single_use (@3)))
       && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@2))
       && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@1)))
   (op @0 { build_zero_cst (TREE_TYPE (@0)); })))
```

The problem is the above does not work as there is an single_use check
on the plus. The single use check was there since the original match
pattern was added.
I am not sure if we should add a special case where in the above
pattern @0 is a shift.
Though changing that will have to wait for GCC 17 I think.

Jeff/Richard,
  What are your thoughts on this? I know Richard had thoughts on some
of the single_use in the match patterns before but I have not tracked
them that well.

Thanks,
Andrew


>
> This optimizes the following code, seen in perlbench:
>
> long
> frob(long x, long y, long z)
> {
>   long ret = (y << 2) + z;
>   long cond = ret != z;
>   if (cond == 0)
>     ret = 0;
>   return ret;
> }
>
> gcc/ChangeLog:
>
>         * match.pd (`((a OP b) + c eq|ne c) ? x : y`): New pattern.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/torture/ifcond-plus-shift-czero.c: New test.
>
> Signed-off-by: Daniel Barboza <[email protected]>
> ---
>  gcc/match.pd                                  | 17 +++++++++++++
>  .../gcc.dg/torture/ifcond-plus-shift-czero.c  | 25 +++++++++++++++++++
>  2 files changed, 42 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/torture/ifcond-plus-shift-czero.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index ccdc1129e23..fdc18b1ef41 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -2824,6 +2824,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>         (le (minus (convert:etype @0) { lo; }) { hi; })
>         (gt (minus (convert:etype @0) { lo; }) { hi; })))))))))
>
> +/* Reduces ((A OP B) + C EQ|NE C) ? X : Y to
> +   A EQ|NE 0 ? x : y, for OP = (lshift, rshift).  */
> +(for cmp (eq ne)
> + (for op (lshift rshift)
> +  (simplify
> +   (cond (cmp:c (plus:c (op @1 @2) @0) @0) @3 @4)
> +    (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@1))
> +        && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@1)))
> +     (with
> +      {
> +       fold_overflow_warning ("assuming signed overflow does not occur "
> +                             "when changing (X << imm) + C1 cmp C1 to "
> +                             "X << imm cmp 0 and X << imm cmp 0 "
> +                             "to X cmp 0",
> +                             WARN_STRICT_OVERFLOW_COMPARISON);  }
> +     (cond (cmp @1 { build_zero_cst (type); }) @3 @4))))))
> +
>  /* X + Z < Y + Z is the same as X < Y when there is no overflow.  */
>  (for op (lt le ge gt)
>   (simplify
> diff --git a/gcc/testsuite/gcc.dg/torture/ifcond-plus-shift-czero.c 
> b/gcc/testsuite/gcc.dg/torture/ifcond-plus-shift-czero.c
> new file mode 100644
> index 00000000000..769412202c3
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/ifcond-plus-shift-czero.c
> @@ -0,0 +1,25 @@
> +/* { dg-do compile } */
> +/* { dg-additional-options "-fdump-tree-phiopt2" } */
> +/* { dg-skip-if "" { *-*-* } { "-O0" "-fno-fat-lto-objects"  } { "" } } */
> +
> +long
> +f1 (long x, long y, long z)
> +{
> +  long ret = (y << 2) + z;
> +  long cond = ret != z;
> +  if (cond == 0)
> +    ret = 0;
> +  return ret;
> +}
> +
> +long
> +f2 (long x, long y, long z)
> +{
> +  long ret = (y >> 2) + z;
> +  long cond = ret != z;
> +  if (cond == 0)
> +    ret = 0;
> +  return ret;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "== 0" 2 "phiopt2" } } */
> --
> 2.43.0
>

Reply via email to