On Fri, Dec 5, 2025 at 6:57 PM Andrew Pinski
<[email protected]> wrote:
>
> On Fri, Dec 5, 2025 at 1:11 PM Daniel Henrique Barboza
> <[email protected]> wrote:
> >
> > Hi,
> >
> > On 12/2/25 5:46 PM, Andrew Pinski wrote:
> > > On Tue, Dec 2, 2025 at 12:11 PM 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
> > >>
> > >>          PR 122608
> > >>
> > >> gcc/ChangeLog:
> > >>
> > >>          * match.pd (`(c ? a : b) op d -> c ? (a op d) : (b op d)`): New
> > >>            pattern.
> > >>
> > >> 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.
> > >>          * gcc.dg/torture/pr122608.c: New test.
> > >>
> > >> Signed-off-by: Daniel Barboza <[email protected]>
> > >> ---
> > >>   gcc/match.pd                             | 10 +++
> > >>   gcc/testsuite/gcc.dg/torture/pr122608.c  | 83 ++++++++++++++++++++++++
> > >>   gcc/testsuite/gcc.target/i386/pr110701.c |  2 +-
> > >>   3 files changed, 94 insertions(+), 1 deletion(-)
> > >>   create mode 100644 gcc/testsuite/gcc.dg/torture/pr122608.c
> > >>
> > >> diff --git a/gcc/match.pd b/gcc/match.pd
> > >> index f164ec59100..9650bbeada7 100644
> > >> --- a/gcc/match.pd
> > >> +++ b/gcc/match.pd
> > >> @@ -6274,6 +6274,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> > >>                 && !expand_vec_cond_expr_p (TREE_TYPE (@1), TREE_TYPE 
> > >> (@0)))))
> > >>      (vec_cond @0 (op! @3 @1) (op! @3 @2)))))
> > >>
> > >> +
> > >> +/* Non-vector comutative sink of binary ops to branches:
> > > spelling: commutative . But these are not commutative (minus and div
> > > are definitely not commutative) but rather just binary operators.
> >
> > I can't recall the context where this 'commutative' comment comes from. I'll
> > remove it.
> >
> > >
> > >> +   (c ? a : b) op d  -->  c ? (a op d) : (b op d)  */
> > >> +(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)
> > >
> > > It might be useful to define a define_operator_list called tcc_binary
> > > like what is done for tcc_comparison. And then just use that operator
> > > list here.
> > >
> > >> + (simplify
> > >> +  (op (cond:s @0 @1 @2) @3)
> > >> +  (cond @0 (op! @1 @3) (op! @2 @3))))
> > >
> > > A few codes missing:
> > > pointer_plus, pointer_diff, mult_highpart, lrotate,  rrotate, complex
> > > All comparison operators (tcc_comparison)
> > >
> > > Some internal functions missing:
> > > COPYSIGN, POW, XORSIGN, HYPOT
> > >
> > > Oh I see you copied this exactly from the vector list and removed
> > > tcc_comparison.
> >
> >
> > I did some tests using current master to verify if these operators were 
> > already
> > being reduced in this pattern or not. Turns out that most of the operators 
> > you
> > mentioned are already being reduced without this patch.
> >
> > The following ops are already being reduced in master:
> >
> > - tcc_comparison
>
> This is from:
> ```
> #if GIMPLE
> /* From fold_binary_op_with_conditional_arg handle the case of
>    rewriting (a ? b : c) > d to a ? (b > d) : (c > d) when the
>    compares simplify.
>    This should be after the boolean comparison simplification so
>    that it can remove the outer comparison before appling it to
>    the inner condtional operands.  */
> (for cmp (simple_comparison)
>  (simplify
>   (cmp:c (cond @0 @1 @2) @3)
>   /* Do not move possibly trapping operations into the conditional as this
>      pessimizes code and causes gimplification issues when applied late.  */
>   (if (!FLOAT_TYPE_P (TREE_TYPE (@3))
>        || !operation_could_trap_p (cmp, true, false, @3))
>    (cond @0 (cmp! @1 @3) (cmp! @2 @3)))))
> #endif
> ```
> Which you could merge your pattern with the above then. But it also
> means you might need a commutative version and one for non-comutative
> which has both versions. or you just support both for all.

At least your new pattern should be next to this pattern for easier to find.

>
> > - pointer_diff
>
> I tried pointer_diff and didn't get it optimized (note long  is not
> exactly right type, it needs to be a define but I can't remember the
> define right now):
> ```
> char *ptr[12];
> __GIMPLE long pointer_diff_test(int a) {
>     _Bool b;
>     long t;
>     char *t1;
>     b = a > 0;
>     t1 = b ? _Literal(char *) & ptr[0] : _Literal(char *) & ptr[1];
>     t = t1 - _Literal(char *) & ptr[0];
>     return t;
> }
> ```
>
> > - mult_highpart
> > - lrotate and rrotate
Sorry pressed send too soon.

I just checked and lrotate/rrotate is not done either:
```
#define F(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; }
F (__ROTATE_RIGHT, rotateright)
F (__ROTATE_LEFT, rotateleft)
```

Nor mult_highpart:
```
#define F(OP,NAME) \
 __GIMPLE int NAME##_test(int a) \
 { _Bool b; \
   int t; \
   b = a > 0; \
   t = b ? 30 : 40; \
   t = t OP 0x7fffffff; \
   return t; }

F (__MULT_HIGHPART, multhighpart)
```

> > - copysign
> > - xorsign
> > - pow
> >
> > As for HYPOT and 'complex', I can add them in the pattern but I didn't 
> > manage to
> > find any example where they would reduce ... I'm either doing something 
> > wrong in
> > the testcode or they aren't reducible via this pattern. In this case I'm 
> > not sure
> > if adding them 'just in case' is a good idea.
> >
> >
> >
> > Thanks,
> >
> > Daniel
> >
> >
> >
> > >
> > > Note pointer_plus is not likely reduce,
> > > pointer_diff could:
> > > (a ? &b[0] : &b[1]) - &b[0]
> > > which should reduce to a ? 0 : 1;
> > > complex could too:
> > > COMPLEX_EXPR<a ? 2.0f : 4.0f, 5.0f> -> a ? COMPLEX_CST<2.0f, 5.0f>,
> > > COMPLEX_CST<4.0f, 5.0f>
> > >
> > > Note these codes/internal functions can be added separately.
> > >
> > >
> > >> +
> > >>   #if GIMPLE
> > >>   (match (nop_atomic_bit_test_and_p @0 @1 @4)
> > >>    (bit_and (convert?@4 (ATOMIC_FETCH_OR_XOR_N @2 INTEGER_CST@0 @3))
> > >> diff --git a/gcc/testsuite/gcc.dg/torture/pr122608.c 
> > >> b/gcc/testsuite/gcc.dg/torture/pr122608.c
> > >> new file mode 100644
> > >> index 00000000000..f8058149e5a
> > >> --- /dev/null
> > >> +++ b/gcc/testsuite/gcc.dg/torture/pr122608.c
> > >> @@ -0,0 +1,83 @@
> > >> +/* { 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; }
> > >> +
> > >> +F (+, plus)
> > >> +F (-, minus)
> > >> +F (*, mult)
> > >> +F (|, bit_ior)
> > >> +F (^, bit_xor)
> > >> +F (/, div)
> > >> +F (%, mod)
> > >> +F (<<, lshift)
> > >> +
> > >> +__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_rshift(int a)
> > >> +{
> > >> +  _Bool b;
> > >> +  int t;
> > >> +  b = a > 0;
> > >> +  t = b ? 2 : 8;
> > >> +  t = t >> 1;
> > >> +  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;
> > >> +}
> > >> +
> > >> +/* { 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 "MIN_EXPR" 0 "optimized" } } */
> > >> +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 0 "optimized" } } */
> > >> diff --git a/gcc/testsuite/gcc.target/i386/pr110701.c 
> > >> b/gcc/testsuite/gcc.target/i386/pr110701.c
> > >> index 3f2cea5c3df..8cd179c3b15 100644
> > >> --- a/gcc/testsuite/gcc.target/i386/pr110701.c
> > >> +++ b/gcc/testsuite/gcc.target/i386/pr110701.c
> > >> @@ -8,5 +8,5 @@ void foo() {
> > >>     *c = d(340, b >= 0) ^ 3;
> > >>   }
> > >>
> > >> -/* { dg-final { scan-assembler "andl\[ \\t]\\\$340," } } */
> > >> +/* { dg-final { scan-assembler-not "andl\[ \\t]\\\$340," } } */
> > >
> > > Changing this scan is most likely incorrect since it is looking for
> > > wrong code. I suspect we should add a runtime testcase (that was
> > > showing the original issue) and remove this test case instead.
> > >
> > > Thanks,
> > > Andrew
> > >
> > >>   /* { dg-final { scan-assembler-not "andw\[ \\t]\\\$340," } } */
> > >> --
> > >> 2.43.0
> > >>
> >

Reply via email to