[gcc r17-3190] tree-optimization: Simplify ((X CMP1 Y) - (X CMP2 Y)) REL 0

Andrea Pinski via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:c59bee6acb24a0d580f4c98a14e879452096220e

commit r17-3190-gc59bee6acb24a0d580f4c98a14e879452096220e
Author: Tudor-Stefan Magirescu <[email protected]>
Date:   Mon Aug 10 18:11:45 2026 +0200

    tree-optimization: Simplify ((X CMP1 Y) - (X CMP2 Y)) REL 0
    
    Add a new match.pd pattern to fold sign-of-difference expressions into
    a single comparison.  The pattern matches differences of two comparisons
    of the same operands, where the comparison pair is one of {gt,lt} or
    {ge,le}.
    
    The pattern cannot be merged into the generic (X - Y) CMP 0 rule
    above it, which is restricted to eq/ne.  Extending that rule to
    lt/le/gt/ge would defeat ABS_EXPR synthesis in
    fold_cond_expr_with_comparison for expressions of the form
    (X - Y) < 0 ? (Y - X) : (X - Y).  Matching the full comparison
    structure avoids this regression.
    
    Bootstrapped and tested on x86_64-linux-gnu.
    
    gcc/ChangeLog:
    
            * match.pd (((X CMP1 Y) - (X CMP2 Y)) REL 0): New pattern.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.c-torture/execute/subcmp-1.c: New test.
            * gcc.dg/tree-ssa/subcmp-1.c: New test.
    
    Signed-off-by: Tudor-Stefan Magirescu <[email protected]>

Diff:
---
 gcc/match.pd                                   |  15 +++
 gcc/testsuite/gcc.c-torture/execute/subcmp-1.c |  55 +++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/subcmp-1.c       | 131 +++++++++++++++++++++++++
 3 files changed, 201 insertions(+)

diff --git a/gcc/match.pd b/gcc/match.pd
index 0ba97b32cb13..50e731770228 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7599,6 +7599,21 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (if (single_use (@2))
     (cmp @0 @1)))))
 
+/* Fold ((X CMP1 Y) - (X CMP2 Y)) REL 0 into a single comparison of X and Y,
+   e.g., ((X > Y) - (X < Y)) < 0 to X < Y.  This cannot be merged into the
+   generic X - Y CMP 0 rule above as it would prevent ABS_EXPR synthesis in
+   fold_cond_expr_with_comparison.  */
+(for rel (lt le gt ge)
+ (for cmp1 (gt ge)
+      cmp2 (lt le)
+  (simplify
+   (rel (minus@2 (convert? (cmp1:c @0 @1))
+		 (convert? (cmp2:c @0 @1))) integer_zerop)
+    (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+	 && !TYPE_UNSIGNED (TREE_TYPE (@2))
+	 && TYPE_PRECISION (TREE_TYPE (@2)) > 1)
+     (rel @0 @1)))))
+
 /* Simplify (x < 0) ^ (y < 0) to (x ^ y) < 0 and
    (x >= 0) ^ (y >= 0) to (x ^ y) < 0.  */
 (for cmp (lt ge)
diff --git a/gcc/testsuite/gcc.c-torture/execute/subcmp-1.c b/gcc/testsuite/gcc.c-torture/execute/subcmp-1.c
new file mode 100644
index 000000000000..4682246c3552
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/subcmp-1.c
@@ -0,0 +1,55 @@
+#define func(vol, op1, op2, op3)	\
+_Bool op1##_##op2##_##op3##_##vol (int a, int b)	\
+{					\
+ vol _Bool x = op_##op1(a, b);		\
+ vol _Bool y = op_##op2(a, b);		\
+ return op_##op3(x - y, 0);		\
+}
+
+#define op_lt(a, b) ((a) < (b))
+#define op_le(a, b) ((a) <= (b))
+#define op_gt(a, b) ((a) > (b))
+#define op_ge(a, b) ((a) >= (b))
+
+#define funcs(a) \
+ a(gt,lt,lt) \
+ a(gt,lt,le) \
+ a(gt,lt,gt) \
+ a(gt,lt,ge) \
+  \
+ a(ge,le,lt) \
+ a(ge,le,le) \
+ a(ge,le,gt) \
+ a(ge,le,ge) \
+  \
+ a(lt,gt,lt) \
+ a(lt,gt,le) \
+ a(lt,gt,gt) \
+ a(lt,gt,ge) \
+  \
+ a(le,ge,lt) \
+ a(le,ge,le) \
+ a(le,ge,gt) \
+ a(le,ge,ge) \
+
+#define funcs1(a,b,c) \
+func(,a,b,c) \
+func(volatile,a,b,c)
+
+funcs(funcs1)
+
+#define test(op1,op2,op3)			\
+do {						\
+  if (op1##_##op2##_##op3##_(x,y)		\
+      != op1##_##op2##_##op3##_volatile(x,y))	\
+    __builtin_abort();				\
+} while(0);
+
+int main()
+{
+  for(int x = -10; x < 10; x++)
+    for(int y = -10; y < 10; y++)
+    {
+        funcs(test)
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/subcmp-1.c b/gcc/testsuite/gcc.dg/tree-ssa/subcmp-1.c
new file mode 100644
index 000000000000..489cf4c1f406
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/subcmp-1.c
@@ -0,0 +1,131 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+_Bool subgtlt_lt(int a00, int b00)
+{
+  _Bool x00 = a00 > b00;
+  _Bool y00 = a00 < b00;
+  return x00 - y00 < 0;
+}
+/* { dg-final { scan-tree-dump "a00_\[0-9\]+.D. < b00_\[0-9\]+.D.|b00_\[0-9\]+.D. > a00_\[0-9\]+.D." "optimized" } } */
+
+_Bool subgtlt_le(int a01, int b01)
+{
+  _Bool x01 = a01 > b01;
+  _Bool y01 = a01 < b01;
+  return x01 - y01 <= 0;
+}
+/* { dg-final { scan-tree-dump "a01_\[0-9\]+.D. <= b01_\[0-9\]+.D.|b01_\[0-9\]+.D. >= a01_\[0-9\]+.D." "optimized" } } */
+
+_Bool subgtlt_gt(int a02, int b02)
+{
+  _Bool x02 = a02 > b02;
+  _Bool y02 = a02 < b02;
+  return x02 - y02 > 0;
+}
+/* { dg-final { scan-tree-dump "a02_\[0-9\]+.D. > b02_\[0-9\]+.D.|b02_\[0-9\]+.D. < a02_\[0-9\]+.D." "optimized" } } */
+
+_Bool subgtlt_ge(int a03, int b03)
+{
+  _Bool x03 = a03 > b03;
+  _Bool y03 = a03 < b03;
+  return x03 - y03 >= 0;
+}
+/* { dg-final { scan-tree-dump "a03_\[0-9\]+.D. >= b03_\[0-9\]+.D.|b03_\[0-9\]+.D. <= a03_\[0-9\]+.D." "optimized" } } */
+
+_Bool subgele_lt(int a04, int b04)
+{
+  _Bool x04 = a04 >= b04;
+  _Bool y04 = a04 <= b04;
+  return x04 - y04 < 0;
+}
+/* { dg-final { scan-tree-dump "a04_\[0-9\]+.D. < b04_\[0-9\]+.D.|b04_\[0-9\]+.D. > a04_\[0-9\]+.D." "optimized" } } */
+
+_Bool subgele_le(int a05, int b05)
+{
+  _Bool x05 = a05 >= b05;
+  _Bool y05 = a05 <= b05;
+  return x05 - y05 <= 0;
+}
+/* { dg-final { scan-tree-dump "a05_\[0-9\]+.D. <= b05_\[0-9\]+.D.|b05_\[0-9\]+.D. >= a05_\[0-9\]+.D." "optimized" } } */
+
+_Bool subgele_gt(int a06, int b06)
+{
+  _Bool x06 = a06 >= b06;
+  _Bool y06 = a06 <= b06;
+  return x06 - y06 > 0;
+}
+/* { dg-final { scan-tree-dump "a06_\[0-9\]+.D. > b06_\[0-9\]+.D.|b06_\[0-9\]+.D. < a06_\[0-9\]+.D." "optimized" } } */
+
+_Bool subgele_ge(int a07, int b07)
+{
+  _Bool x07 = a07 >= b07;
+  _Bool y07 = a07 <= b07;
+  return x07 - y07 >= 0;
+}
+/* { dg-final { scan-tree-dump "a07_\[0-9\]+.D. >= b07_\[0-9\]+.D.|b07_\[0-9\]+.D. <= a07_\[0-9\]+.D." "optimized" } } */
+
+_Bool subltgt_lt(int a08, int b08)
+{
+  _Bool x08 = a08 < b08;
+  _Bool y08 = a08 > b08;
+  return x08 - y08 < 0;
+}
+/* { dg-final { scan-tree-dump "a08_\[0-9\]+.D. > b08_\[0-9\]+.D.|b08_\[0-9\]+.D. < a08_\[0-9\]+.D." "optimized" } } */
+
+_Bool subltgt_le(int a09, int b09)
+{
+  _Bool x09 = a09 < b09;
+  _Bool y09 = a09 > b09;
+  return x09 - y09 <= 0;
+}
+/* { dg-final { scan-tree-dump "a09_\[0-9\]+.D. >= b09_\[0-9\]+.D.|b09_\[0-9\]+.D. <= a09_\[0-9\]+.D." "optimized" } } */
+
+_Bool subltgt_gt(int a10, int b10)
+{
+  _Bool x10 = a10 < b10;
+  _Bool y10 = a10 > b10;
+  return x10 - y10 > 0;
+}
+/* { dg-final { scan-tree-dump "a10_\[0-9\]+.D. < b10_\[0-9\]+.D.|b10_\[0-9\]+.D. > a10_\[0-9\]+.D." "optimized" } } */
+
+_Bool subltgt_ge(int a11, int b11)
+{
+  _Bool x11 = a11 < b11;
+  _Bool y11 = a11 > b11;
+  return x11 - y11 >= 0;
+}
+/* { dg-final { scan-tree-dump "a11_\[0-9\]+.D. <= b11_\[0-9\]+.D.|b11_\[0-9\]+.D. >= a11_\[0-9\]+.D." "optimized" } } */
+
+_Bool sublege_lt(int a12, int b12)
+{
+  _Bool x12 = a12 <= b12;
+  _Bool y12 = a12 >= b12;
+  return x12 - y12 < 0;
+}
+/* { dg-final { scan-tree-dump "a12_\[0-9\]+.D. > b12_\[0-9\]+.D.|b12_\[0-9\]+.D. < a12_\[0-9\]+.D." "optimized" } } */
+
+_Bool sublege_le(int a13, int b13)
+{
+  _Bool x13 = a13 <= b13;
+  _Bool y13 = a13 >= b13;
+  return x13 - y13 <= 0;
+}
+/* { dg-final { scan-tree-dump "a13_\[0-9\]+.D. >= b13_\[0-9\]+.D.|b13_\[0-9\]+.D. <= a13_\[0-9\]+.D." "optimized" } } */
+
+_Bool sublege_gt(int a14, int b14)
+{
+  _Bool x14 = a14 <= b14;
+  _Bool y14 = a14 >= b14;
+  return x14 - y14 > 0;
+}
+/* { dg-final { scan-tree-dump "a14_\[0-9\]+.D. < b14_\[0-9\]+.D.|b14_\[0-9\]+.D. > a14_\[0-9\]+.D." "optimized" } } */
+
+_Bool sublege_ge(int a15, int b15)
+{
+  _Bool x15 = a15 <= b15;
+  _Bool y15 = a15 >= b15;
+  return x15 - y15 >= 0;
+}
+/* { dg-final { scan-tree-dump "a15_\[0-9\]+.D. <= b15_\[0-9\]+.D.|b15_\[0-9\]+.D. >= a15_\[0-9\]+.D." "optimized" } } */
+/* { dg-final { scan-tree-dump-not "_\[0-9\]+ - _\[0-9\]+" "optimized" } } */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.