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.
> - 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
> - 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
> >>
>