On Mon, Dec 29, 2025 at 11:57 AM Daniel Barboza
<[email protected]> wrote:
>
> Add a pattern to handle cases where we have an OP that is
> unconditionally being applied in the result of a gcond. In this case we
> can apply OP to both legs of the conditional. E.g:
>
> t = b ? 10 : 20;
> t = t + 20;
>
> becomes just:
>
> t = b ? 30 : 40
>
> A variant pattern was also added to handle the case where the gcond
> result is used as the second operand. This was needed because most of
> the ops we're handling aren't commutative.
>
>         PR 122608
>
> gcc/ChangeLog:
>
>         * match.pd (`(c ? a : b) op d -> c ? (a op d) : (b op d)`): New
>           pattern.
>           (`d op (c ? a : b) -> c ? (d op a) : (d op b)`): Likewise
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.target/i386/pr110701.c: the pattern added is now folding
>           an XOR into the ifcond and the assembler isn't emitting an
>           'andl' anymore. The test was turned into a runtime test
>           instead.
>         * gcc.dg/torture/pr122608.c: New test.

This is mostly ok from my side except for the testcase change for
pr110701.c. See below; dg-output is not used most of the time.

>
> Signed-off-by: Daniel Barboza <[email protected]>
> ---
>
> Changes from v1:
>
> - changed pr110710.c to be a runtime test
> - pattern now handles pointer_diff, lrotate, rrotate and mult_highpart
> - pattern was moved to be right after a similar pattern that handles
>   simple_comparisons
> - a variant pattern was added: d op (c ? a : b) -> c ? (d op a) : (d op b)
> - v1 link: https://gcc.gnu.org/pipermail/gcc-patches/2025-December/702665.html
>
>
>  gcc/match.pd                             |  17 +++
>  gcc/testsuite/gcc.dg/torture/pr122608.c  | 178 +++++++++++++++++++++++
>  gcc/testsuite/gcc.target/i386/pr110701.c |  13 +-
>  3 files changed, 205 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr122608.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index 45d96844673..9577224305f 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -8603,6 +8603,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>    (if (!FLOAT_TYPE_P (TREE_TYPE (@3))
>         || !operation_could_trap_p (cmp, true, false, @3))
>     (cond @0 (cmp! @1 @3) (cmp! @2 @3)))))
> +
> +/* Similar to above:
> +   (c ? a : b) op d  ->  c ? (a op d) : (b op d)
> +   But with non-vector binary ops, most of them non-commutative.  */
> +(for op (plus minus mult bit_and bit_ior bit_xor
> +        lshift rshift rdiv trunc_div ceil_div floor_div round_div exact_div
> +        trunc_mod ceil_mod floor_mod round_mod min max pointer_diff
> +        lrotate rrotate mult_highpart)
> + (simplify
> +  (op (cond @0 @1 @2) @3)
> +  (cond @0 (op! @1 @3) (op! @2 @3)))
> +
> + /* Support the variant
> +    d op (c ? a : b)  ->  c ? (d op a) : (d op b)  */
> + (simplify
> +  (op @3 (cond @0 @1 @2))
> +  (cond @0 (op! @3 @1) (op! @3 @2))))
>  #endif
>
>  /* Transform comparisons of the form (X & Y) CMP 0 to X CMP2 Z
> diff --git a/gcc/testsuite/gcc.dg/torture/pr122608.c 
> b/gcc/testsuite/gcc.dg/torture/pr122608.c
> new file mode 100644
> index 00000000000..8129a129769
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/pr122608.c
> @@ -0,0 +1,178 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fgimple -fdump-tree-optimized" } */
> +/* { dg-skip-if "" { *-*-* } { "-O0" "-fno-fat-lto-objects" } { "" } } */
> +
> +#define F(OP,NAME) \
> + __GIMPLE int NAME##_test (int a) \
> + { _Bool b; \
> +   int t; \
> +   b = a > 0; \
> +   t = b ? 20 : 40; \
> +   t = t OP 11; \
> +   return t; } \
> + __GIMPLE int NAME##_test2 (int a) \
> + { _Bool b; \
> +   int t; \
> +   b = a > 0; \
> +   t = b ? 2 : 4; \
> +   t = 11 OP t; \
> +   return t; }
> +
> +F (+, plus)
> +F (-, minus)
> +F (*, mult)
> +F (|, bit_ior)
> +F (^, bit_xor)
> +F (/, div)
> +F (%, mod)
> +F (<<, lshift)
> +
> +#define F2(OP,NAME) \
> +__GIMPLE int NAME##_test (int a) \
> + { _Bool b; \
> +   int t; \
> +   b = a > 0; \
> +   t = b ? 20 : 40; \
> +   t = t OP 2; \
> +   return t; } \
> +__GIMPLE int NAME##_test2 (int a) \
> + { _Bool b; \
> +   int t; \
> +   b = a > 0; \
> +   t = b ? 2 : 3; \
> +   t = 11 OP 2; \
> +   return t; }
> +F2 (__ROTATE_RIGHT, rotateright)
> +F2 (__ROTATE_LEFT, rotateleft)
> +
> +__GIMPLE int test_and (int a)
> +{
> +  _Bool b;
> +  int t;
> +  b = a > 0;
> +  t = b ? 1 : 3;
> +  t = t & 3;
> +  return t;
> +}
> +
> +__GIMPLE int test_and2 (int a)
> +{
> +  _Bool b;
> +  int t;
> +  b = a > 0;
> +  t = b ? 1 : 3;
> +  t = 3 & t;
> +  return t;
> +}
> +
> +__GIMPLE int test_rshift (int a)
> +{
> +  _Bool b;
> +  int t;
> +  b = a > 0;
> +  t = b ? 2 : 8;
> +  t = t >> 1;
> +  return t;
> +}
> +
> +__GIMPLE int test_rshift2 (int a)
> +{
> +  _Bool b;
> +  int t;
> +  b = a > 0;
> +  t = b ? 1 : 2;
> +  t = 8 >> t;
> +  return t;
> +}
> +
> +static int min (int a, int b)
> +{
> +  return a < b ? a : b;
> +}
> +
> +static int max (int a, int b)
> +{
> +  return a > b ? a : b;
> +}
> +
> +__GIMPLE int min_test (int a)
> +{
> +  _Bool b;
> +  int t;
> +  b = a > 0;
> +  t = b ? 2 : 4;
> +  t = min (t, 3);
> +  return t;
> +}
> +
> +__GIMPLE int max_test (int a)
> +{
> +  _Bool b;
> +  int t;
> +  b = a > 0;
> +  t = b ? 2 : 4;
> +  t = max (t, 3);
> +  return t;
> +}
> +
> +char *ptr[12];
> +typedef __PTRDIFF_TYPE__ ptrdiff_t;
> +
> +__GIMPLE ptrdiff_t pointer_diff_test (int a)
> +{
> +  _Bool b;
> +  ptrdiff_t t;
> +  char *t1;
> +  b = a > 0;
> +  t1 = b ? _Literal(char *) & ptr[0] : _Literal(char *) & ptr[1];
> +  t = t1 - _Literal(char *) & ptr[0];
> +  return t;
> +}
> +
> +__GIMPLE ptrdiff_t pointer_diff_test2 (int a)
> +{
> +  _Bool b;
> +  ptrdiff_t t;
> +  char *t1;
> +  b = a > 0;
> +  t1 = b ? _Literal(char *) & ptr[0] : _Literal(char *) & ptr[1];
> +  t = _Literal(char *) & ptr[1] - t1;
> +  return t;
> +}
> +
> +__GIMPLE int mulhighpart_test (int a)
> +{
> +  _Bool b;
> +  int t;
> +  b = a > 0;
> +  t = b ? 30 : 40;
> +  t = t __MULT_HIGHPART 0x7fffffff;
> +  return t;
> +}
> +
> +__GIMPLE int mulhighpart_test2 (int a)
> +{
> +  _Bool b;
> +  int t;
> +  b = a > 0;
> +  t = b ? 0x5fffffff : 0x7fffffff;
> +  t = 40 __MULT_HIGHPART t;
> +  return t;
> +}
> +
> +/* { dg-final { scan-tree-dump-times " \\+ " 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times " \\- " 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times " \\* " 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times " \\| " 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times " \\^ " 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times " & " 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times " / " 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times " % " 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times " >> " 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times " r>> " 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times " h\\* " 0 "optimized" } } */
> +
> +/* Note: pointer_diff_tests adds a lshift each when they succeed */
> +/* { dg-final { scan-tree-dump-times " << " 2 "optimized" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr110701.c 
> b/gcc/testsuite/gcc.target/i386/pr110701.c
> index 3f2cea5c3df..ae74b57afa7 100644
> --- a/gcc/testsuite/gcc.target/i386/pr110701.c
> +++ b/gcc/testsuite/gcc.target/i386/pr110701.c
> @@ -1,12 +1,19 @@
> -/* { dg-do compile } */
> +/* { dg-do run } */
>  /* { dg-options "-O2" } */
> +#include <stdio.h>
> +
>  int a;
>  long b;
>  int *c = &a;
>  short d(short e, short f) { return e * f; }
>  void foo() {
>    *c = d(340, b >= 0) ^ 3;
> +  printf("%d\n", a);
> +}
> +
> +int main()
> +{
> +  foo();
>  }
>
> -/* { dg-final { scan-assembler "andl\[ \\t]\\\$340," } } */
> -/* { dg-final { scan-assembler-not "andw\[ \\t]\\\$340," } } */
> +/* { dg-output "343" } */

We normally don't use dg-output in the GCC testsuite.  There are a few
exceptions; mostly in the libstdc++, fortran testsuites and for the
sanitizers testcases.
So the best approach would be:
```
__attribute__((noipa))
void foo() {
    *c = d(340, b >= 0) ^ 3;
}

int main()
{
  foo();
  if (a != 343)
    __builtin_abort();
}
```

Hopefully I did that correctly. But you should get the idea.

Thanks,
Andrew Pinski

> --
> 2.43.0
>

Reply via email to