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