Hi,

As suggested in the first version I have used the match pattern to recognize
the spaceship pattern.

cc'ed the maintainers of x86, aarch64 and s390 port to validate predicate added
in target-supports.exp.

Bootstrapped and regtested on x86_64-linux-gnu and powerpc64le-linux-gnu with
no regressions. Please review.

Changes from v1:
* Added tests for all possible spaceship operator variants in c for
signed/unsigned int.
* Added a new effective target predicate for in target-supports.exp. Since I saw
aarch64, x86 and s390 implement this operator, I have added those in the
targets.
* Use match.pd to detect the cfg more robustly.

Thanks and regards,
Avinash Jayakar

There are certain patterns that are not recognized by the method
optimize_spaceship. For example,
  a == b ? 0 : (a > b) : 1 : -1;
is rightly recognized as spaceship operator. But
  a <= b ? -(a < b) : 1 or
  a >= b ? (a > b) : -1
is not being currently recognized.

This patch recognizes such patterns and chooses to emit the spaceship
optab if target supports it, which improves code-generation for such
targets.

2026-02-24  Avinash Jayakar  <[email protected]>

gcc/ChangeLog:
        * match.pd: New match patterns to recognize spaceship variants.
        * tree-ssa-math-opts.cc (gimple_spaceship): Match function declaration.
        (match_spaceship): New function to recognize spaceship given phi node.
        (math_opts_dom_walker::after_dom_children): Add match_spaceship check.

gcc/testsuite/ChangeLog:
        * lib/target-supports.exp (check_effective_target_spaceship): Add new
        proc for spaceship optab. x86, aarch64 and s390 included.
        * gcc.dg/spaceship_int_variants.c: New test.
        * gcc.dg/spaceship_uint_variants.c: New test.
---
 gcc/match.pd                                  |   8 ++
 gcc/testsuite/gcc.dg/spaceship_int_variants.c | 102 ++++++++++++++++++
 .../gcc.dg/spaceship_uint_variants.c          | 102 ++++++++++++++++++
 gcc/testsuite/lib/target-supports.exp         |   8 ++
 gcc/tree-ssa-math-opts.cc                     |  33 +++++-
 5 files changed, 251 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/spaceship_int_variants.c
 create mode 100644 gcc/testsuite/gcc.dg/spaceship_uint_variants.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 7f16fd4e081..0bcb5c0fe77 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3661,6 +3661,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
            @2)
    (if (wi::eq_p (wi::to_wide (@1), wi::to_wide (@3))))))
 
+(if (INTEGRAL_TYPE_P (type))
+  (for op (lt ne)
+  (match (spaceship @0 @1)
+    (cond^ (le @0 @1) (negate (convert? (op @0 @1))) integer_onep)))
+  (for op (gt ne)
+  (match (spaceship @0 @1)
+    (cond^ (ge @0 @1) (convert? (op @0 @1)) integer_minus_onep))))
+
 /* Saturation sub for signed integer.  */
 (if (INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type))
  (match (signed_integer_sat_sub @0 @1)
diff --git a/gcc/testsuite/gcc.dg/spaceship_int_variants.c 
b/gcc/testsuite/gcc.dg/spaceship_int_variants.c
new file mode 100644
index 00000000000..bf2fee63c17
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spaceship_int_variants.c
@@ -0,0 +1,102 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target spaceship } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times {\.SPACESHIP \([^,]+, [^,]+, -1\)} 24 
optimized } } */
+
+int sp1 (int a, int b)
+{
+    return a < b ? -1 : a > b ? 1 : 0;
+}
+int sp1_1 (int a, int b)
+{
+    return a < b ? -1 : a == b ? 0 : 1;
+}
+int sp1_2 (int a, int b)
+{
+    return a < b ? -1 : a != b ? 1 : 0;
+}
+int sp1_3 (int a, int b)
+{
+    return a < b ? -1 : a <= b ? 0 : 1;
+}
+int sp2 (int a, int b)
+{
+    return a == b ? 0 : a > b ? 1 : -1;
+}
+int sp2_1 (int a, int b)
+{
+    return a == b ? 0 : a < b ? -1 : 1;
+}
+int sp2_2 (int a, int b)
+{
+    return a == b ? 0 : a >= b ? 1 : -1;
+}
+int sp2_3 (int a, int b)
+{
+    return a == b ? 0 : a <= b ? -1 : 1;
+}
+int sp3 (int a, int b)
+{
+    return a != b ? (a > b ? 1 : -1) : 0;
+}
+int sp3_1 (int a, int b)
+{
+    return a != b ? (a < b ? -1 : 1) : 0;
+}
+int sp3_2 (int a, int b)
+{
+    return a != b ? (a >= b ? 1 : -1) : 0;
+}
+int sp3_3 (int a, int b)
+{
+    return a != b ? (a <= b ? -1 : 1) : 0;
+}
+int sp4 (int a, int b)
+{
+    return a > b ? 1 : a == b ? 0 : -1;
+}
+int sp4_1 (int a, int b)
+{
+    return a > b ? 1 : a < b ? -1 : 0;
+}
+int sp4_2 (int a, int b)
+{
+    return a > b ? 1 : a != b ? -1 : 0;
+}
+int sp4_3 (int a, int b)
+{
+    return a > b ? 1 : a >= b ? 0 : -1;
+}
+int sp5 (int a, int b)
+{
+    return a <= b ? (a == b ? 0 : -1) : 1;
+}
+int sp5_1 (int a, int b)
+{
+    return a <= b ? (a >= b ? 0 : -1) : 1;
+}
+int sp5_2 (int a, int b)
+{
+    return a <= b ? (a != b ? -1 : 0) : 1;
+}
+int sp5_3 (int a, int b)
+{
+    return a <= b ? (a < b ? -1 : 0) : 1;
+}
+int sp6 (int a, int b)
+{
+    return a >= b ? (a == b ? 0 : 1) : -1;
+}
+int sp6_1 (int a, int b)
+{
+    return a >= b ? (a != b ? 1 : 0) : -1;
+}
+int sp6_2 (int a, int b)
+{
+    return a >= b ? (a <= b ? 0 : 1) : -1;
+}
+int sp6_3 (int a, int b)
+{
+    return a >= b ? (a > b ? 1 : 0) : -1;
+}
+
diff --git a/gcc/testsuite/gcc.dg/spaceship_uint_variants.c 
b/gcc/testsuite/gcc.dg/spaceship_uint_variants.c
new file mode 100644
index 00000000000..ee18e94185e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spaceship_uint_variants.c
@@ -0,0 +1,102 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target spaceship } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times {\.SPACESHIP \([^,]+, [^,]+, 1\)} 24 
optimized } } */
+
+int sp1 (unsigned int a, unsigned int b)
+{
+    return a < b ? -1 : a > b ? 1 : 0;
+}
+int sp1_1 (unsigned int a, unsigned int b)
+{
+    return a < b ? -1 : a == b ? 0 : 1;
+}
+int sp1_2 (unsigned int a, unsigned int b)
+{
+    return a < b ? -1 : a != b ? 1 : 0;
+}
+int sp1_3 (unsigned int a, unsigned int b)
+{
+    return a < b ? -1 : a <= b ? 0 : 1;
+}
+int sp2 (unsigned int a, unsigned int b)
+{
+    return a == b ? 0 : a > b ? 1 : -1;
+}
+int sp2_1 (unsigned int a, unsigned int b)
+{
+    return a == b ? 0 : a < b ? -1 : 1;
+}
+int sp2_2 (unsigned int a, unsigned int b)
+{
+    return a == b ? 0 : a >= b ? 1 : -1;
+}
+int sp2_3 (unsigned int a, unsigned int b)
+{
+    return a == b ? 0 : a <= b ? -1 : 1;
+}
+int sp3 (unsigned int a, unsigned int b)
+{
+    return a != b ? (a > b ? 1 : -1) : 0;
+}
+int sp3_1 (unsigned int a, unsigned int b)
+{
+    return a != b ? (a < b ? -1 : 1) : 0;
+}
+int sp3_2 (unsigned int a, unsigned int b)
+{
+    return a != b ? (a >= b ? 1 : -1) : 0;
+}
+int sp3_3 (unsigned int a, unsigned int b)
+{
+    return a != b ? (a <= b ? -1 : 1) : 0;
+}
+int sp4 (unsigned int a, unsigned int b)
+{
+    return a > b ? 1 : a == b ? 0 : -1;
+}
+int sp4_1 (unsigned int a, unsigned int b)
+{
+    return a > b ? 1 : a < b ? -1 : 0;
+}
+int sp4_2 (unsigned int a, unsigned int b)
+{
+    return a > b ? 1 : a != b ? -1 : 0;
+}
+int sp4_3 (unsigned int a, unsigned int b)
+{
+    return a > b ? 1 : a >= b ? 0 : -1;
+}
+int sp5 (unsigned int a, unsigned int b)
+{
+    return a <= b ? (a == b ? 0 : -1) : 1;
+}
+int sp5_1 (unsigned int a, unsigned int b)
+{
+    return a <= b ? (a >= b ? 0 : -1) : 1;
+}
+int sp5_2 (unsigned int a, unsigned int b)
+{
+    return a <= b ? (a != b ? -1 : 0) : 1;
+}
+int sp5_3 (unsigned int a, unsigned int b)
+{
+    return a <= b ? (a < b ? -1 : 0) : 1;
+}
+int sp6 (unsigned int a, unsigned int b)
+{
+    return a >= b ? (a == b ? 0 : 1) : -1;
+}
+int sp6_1 (unsigned int a, unsigned int b)
+{
+    return a >= b ? (a != b ? 1 : 0) : -1;
+}
+int sp6_2 (unsigned int a, unsigned int b)
+{
+    return a >= b ? (a <= b ? 0 : 1) : -1;
+}
+int sp6_3 (unsigned int a, unsigned int b)
+{
+    return a >= b ? (a > b ? 1 : 0) : -1;
+}
+
diff --git a/gcc/testsuite/lib/target-supports.exp 
b/gcc/testsuite/lib/target-supports.exp
index 855bdbcf55a..5fc3a0e59b7 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -10403,6 +10403,14 @@ proc check_effective_target_sync_long_long_runtime { } 
{
     }
 }
 
+# Return 1 if target supports spaceship optab
+
+proc check_effective_target_spaceship { } {   
+  return [expr { [check_effective_target_x86]
+                   || [istarget aarch64*-*-*]
+                   || [istarget s390*-*-*] }]
+}
+
 # Return 1 if the target supports byte swap instructions.
 
 proc check_effective_target_bswap { } {
diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
index bb67dca560b..e9fc55708dd 100644
--- a/gcc/tree-ssa-math-opts.cc
+++ b/gcc/tree-ssa-math-opts.cc
@@ -4121,6 +4121,7 @@ extern bool gimple_unsigned_integer_sat_add (tree, tree*, 
tree (*)(tree));
 extern bool gimple_unsigned_integer_sat_sub (tree, tree*, tree (*)(tree));
 extern bool gimple_unsigned_integer_sat_trunc (tree, tree*, tree (*)(tree));
 extern bool gimple_unsigned_integer_sat_mul (tree, tree*, tree (*)(tree));
+extern bool gimple_spaceship (tree, tree*, tree (*)(tree));
 
 extern bool gimple_signed_integer_sat_add (tree, tree*, tree (*)(tree));
 extern bool gimple_signed_integer_sat_sub (tree, tree*, tree (*)(tree));
@@ -4330,6 +4331,34 @@ match_saturation_mul (gimple_stmt_iterator *gsi, gphi 
*phi)
                                                        ops[1]);
 }
 
+static bool
+match_spaceship (gimple_stmt_iterator *gsi, gphi *phi)
+{
+  if (gimple_phi_num_args (phi) != 2)
+    return false;
+  tree ops[2];
+  tree phi_result = gimple_phi_result (phi);
+
+  if (!gimple_spaceship (phi_result, ops, NULL))
+    return false;
+
+  if (TYPE_MODE (TREE_TYPE (phi_result)) != TYPE_MODE (TREE_TYPE (ops[0])))
+    return false;
+
+  if (optab_handler (spaceship_optab,
+                    TYPE_MODE (TREE_TYPE (phi_result))) == CODE_FOR_nothing)
+    return false;
+
+  gcall *call = gimple_build_call_internal (IFN_SPACESHIP, 3, ops[0], ops[1],
+                                           build_int_cst
+                                           (integer_type_node,
+                                            TYPE_UNSIGNED (TREE_TYPE (ops[0]))
+                                            ? 1 : -1));
+  gimple_call_set_lhs (call, phi_result);
+  gsi_insert_before (gsi, call, GSI_SAME_STMT);
+  return true;
+}
+
 /*
  * Try to match saturation unsigned sub.
  *  <bb 2> [local count: 1073741824]:
@@ -6508,11 +6537,11 @@ math_opts_dom_walker::after_dom_children (basic_block 
bb)
 
       gimple_stmt_iterator gsi = gsi_after_labels (bb);
       gphi *phi = psi.phi ();
-
       if (match_saturation_add (&gsi, phi)
          || match_saturation_sub (&gsi, phi)
          || match_saturation_trunc (&gsi, phi)
-         || match_saturation_mul (&gsi, phi))
+         || match_saturation_mul (&gsi, phi)
+         || match_spaceship (&gsi, phi))
        remove_phi_node (&psi, /* release_lhs_p */ false);
     }
 
-- 
2.51.0

Reply via email to