]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[PATCH v4] match.pd: (c?a:b) op d -> c ? (a op d):(b op d) [PR122608]
authorDaniel Barboza <daniel.barboza@oss.qualcomm.com>
Sun, 4 Jan 2026 17:44:51 +0000 (10:44 -0700)
committerJeff Law <jeffrey.law@oss.qualcomm.com>
Sun, 4 Jan 2026 17:46:41 +0000 (10:46 -0700)
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 tree-optimization/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.

Signed-off-by: Daniel Barboza <daniel.barboza@oss.qualcomm.com>
gcc/match.pd
gcc/testsuite/gcc.dg/torture/pr122608.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr110701.c

index 7860ceab870f5d7e4c008d450b02d8675b939f00..ccdc1129e23e348c9fffda67e504c0c1032d2611 100644 (file)
@@ -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 (file)
index 0000000..d427373
--- /dev/null
@@ -0,0 +1,189 @@
+/* { 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;
+}
+
+#if __INT_WIDTH__ == 8
+#define HIGH1 0x7f
+#define HIGH2 0x5f
+#elif __INT_WIDTH__ == 16
+#define HIGH1 0x7fff
+#define HIGH2 0x5fff
+#else
+#define HIGH1 0x7fffffff
+#define HIGH2 0x5fffffff
+#endif
+
+__GIMPLE int multhighpart_test (int a)
+{
+  _Bool b;
+  int t;
+  b = a > 0;
+  t = b ? 30 : 40;
+  t = t __MULT_HIGHPART HIGH1;
+  return t;
+}
+
+__GIMPLE int multhighpart_test2 (int a)
+{
+  _Bool b;
+  int t;
+  b = a > 0;
+  t = b ? HIGH2 : HIGH1;
+  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" } } */
index 3f2cea5c3df07700f96975a9a2523f13a194b1f6..9ec53f7a6357d08f11a47233b2161ffa80d8b4d9 100644 (file)
@@ -1,12 +1,20 @@
-/* { dg-do compile } */
+/* { dg-do run } */
 /* { dg-options "-O2" } */
+
 int a;
 long b;
 int *c = &a;
 short d(short e, short f) { return e * f; }
+
+__attribute__((noipa))
 void foo() {
   *c = d(340, b >= 0) ^ 3;
 }
 
-/* { dg-final { scan-assembler "andl\[ \\t]\\\$340," } } */
-/* { dg-final { scan-assembler-not "andw\[ \\t]\\\$340," } } */
+int main()
+{
+  foo();
+
+  if (a != 343)
+    __builtin_abort();
+}