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:
+ (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)
+ (simplify
+ (op (cond:s @0 @1 @2) @3)
+ (cond @0 (op! @1 @3) (op! @2 @3))))
+
#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," } } */
/* { dg-final { scan-assembler-not "andw\[ \\t]\\\$340," } } */
--
2.43.0