On Mon, Jun 15, 2026 at 5:51 AM Avinash Jayakar <[email protected]> wrote:
>
> Hi,
>
> Thank you Andrew and Stefan for reviewing v3 of this patch.
>
> Incorporated the changes for this patch mentioned in v3:
> https://gcc.gnu.org/pipermail/gcc-patches/2026-June/720097.html
> https://gcc.gnu.org/pipermail/gcc-patches/2026-June/720124.html
>
> Bootstrapped and regtested on x86_64-linux and aarch64-linux without
> regressions. Ok for trunk?
>
> Changes from v3:
> * Update target flag for s390 in target-supports.exp
> * Use canonical way of iterating over the scalar_int_modes.
> * Simplify building of cast stmts to promoted type and the call to
> spaceship op.
>
> Changes from v2:
> * Relax type restrictions for recognizing spaceship.
> * Check if wider type for spaceship exists, and promote to it if
> possible.
> * Add test cases for mixed types.
>
> 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-06-15 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.dg/spaceship_mixed_variants.c: New test.
> ---
> gcc/match.pd | 18 +
> gcc/testsuite/gcc.dg/spaceship_int_variants.c | 101 ++++++
> .../gcc.dg/spaceship_mixed_variants.c | 324 ++++++++++++++++++
> .../gcc.dg/spaceship_uint_variants.c | 101 ++++++
> gcc/testsuite/lib/target-supports.exp | 10 +
> gcc/tree-ssa-math-opts.cc | 91 ++++-
> 6 files changed, 644 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/gcc.dg/spaceship_int_variants.c
> create mode 100644 gcc/testsuite/gcc.dg/spaceship_mixed_variants.c
> create mode 100644 gcc/testsuite/gcc.dg/spaceship_uint_variants.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index d0d37116ddf..216b2ab8198 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -236,6 +236,24 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> && !TYPE_UNSIGNED (TREE_TYPE (@0)))
> (abs @0)))
>
> +/* Following match patterns are used by the match_spaceship function to
> detect
> + all possible spaceship combinations. */
> +#if GIMPLE
> +(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 (lt ne)
> + (match (spaceship @0 @1)
> + (cond^ (le @1 @0) (convert? (op @1 @0)) integer_minus_onep)))
> + (for op (gt ne)
> + (match (spaceship @0 @1)
> + (cond^ (ge @0 @1) (convert? (op @0 @1)) integer_minus_onep))))
> + (for op (gt ne)
> + (match (spaceship @0 @1)
> + (cond^ (ge @1 @0) (negate (convert? (op @1 @0))) integer_onep)))
> +#endif
> +
> /* Simplifications of operations with one constant operand and
> simplifications to constants or single values. */
>
> 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..41cd78354d7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/spaceship_int_variants.c
> @@ -0,0 +1,101 @@
> +/* { 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_mixed_variants.c
> b/gcc/testsuite/gcc.dg/spaceship_mixed_variants.c
> new file mode 100644
> index 00000000000..a6d7c96363a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/spaceship_mixed_variants.c
> @@ -0,0 +1,324 @@
> +/* { dg-do compile } */
> +/* { dg-require-effective-target spaceship } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-times {\.SPACESHIP \([^,]+, [^,]+, -1\)} 64
> optimized } } */
> +
> +signed char sp1_1 (signed char a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_2 (signed char a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_3 (signed char a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_4 (signed char a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_5 (short a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_6 (short a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_7 (short a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_8 (short a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_9 (int a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_10 (int a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_11 (int a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_12 (int a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_13 (long long a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_14 (long long a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_15 (long long a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +signed char sp1_16 (long long a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_1 (signed char a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_2 (signed char a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_3 (signed char a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_4 (signed char a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_5 (short a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_6 (short a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_7 (short a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_8 (short a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_9 (int a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_10 (int a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_11 (int a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_12 (int a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_13 (long long a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_14 (long long a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_15 (long long a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +short sp2_16 (long long a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_1 (signed char a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_2 (signed char a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_3 (signed char a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_4 (signed char a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_5 (short a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_6 (short a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_7 (short a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_8 (short a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_9 (int a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_10 (int a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_11 (int a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_12 (int a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_13 (long long a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_14 (long long a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_15 (long long a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +int sp3_16 (long long a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_1 (signed char a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_2 (signed char a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_3 (signed char a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_4 (signed char a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_5 (short a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_6 (short a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_7 (short a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_8 (short a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_9 (int a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_10 (int a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_11 (int a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_12 (int a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_13 (long long a, signed char b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_14 (long long a, short b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_15 (long long a, int b)
> +{
> + return a < b ? -1 : a <= b ? 0 : 1;
> +}
> +
> +long long sp4_16 (long long a, long long b)
> +{
> + return a < b ? -1 : a <= b ? 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..360b17c2557
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/spaceship_uint_variants.c
> @@ -0,0 +1,101 @@
> +/* { 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 0298509ae9c..de91038d882 100644
> --- a/gcc/testsuite/lib/target-supports.exp
> +++ b/gcc/testsuite/lib/target-supports.exp
> @@ -10409,6 +10409,16 @@ proc check_effective_target_popcount { } {
> } "" ]
> }
>
> +
> +# Return 1 if target supports spaceship optab
> +
> +proc check_effective_target_spaceship { } {
> + return [expr { [check_effective_target_x86]
> + || [istarget aarch64*-*-*]
> + || [check_effective_target_s390_mvx] }]
> +}
> +
> +
> # Return 1 if the target supports clz on int.
>
> proc check_effective_target_clz { } {
> diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
> index 2f4ee8ac26f..37ca7839dec 100644
> --- a/gcc/tree-ssa-math-opts.cc
> +++ b/gcc/tree-ssa-math-opts.cc
> @@ -115,6 +115,7 @@ along with GCC; see the file COPYING3. If not see
> #include "domwalk.h"
> #include "tree-ssa-math-opts.h"
> #include "dbgcnt.h"
> +#include "langhooks.h"
> #include "cfghooks.h"
>
> /* This structure represents one basic block that either computes a
> @@ -4124,6 +4125,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));
> @@ -4333,6 +4335,92 @@ match_saturation_mul (gimple_stmt_iterator *gsi, gphi
> *phi)
> ops[1]);
> }
>
> +static bool
> +match_spaceship (gimple_stmt_iterator *gsi, gphi *phi)
I missed this in my previous review, Can you add a comment in front of
this function to say what it does with its arguments and what it
returns?
Otherwise ok.
Thanks,
Andrew
> +{
> + 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;
> +
> + /* Allow different modes as long as both are integral types. */
> + if (!INTEGRAL_TYPE_P (TREE_TYPE (phi_result))
> + || !INTEGRAL_TYPE_P (TREE_TYPE (ops[0])))
> + return false;
> +
> + tree ops_type = TREE_TYPE (ops[0]);
> + machine_mode ops_mode = TYPE_MODE (ops_type);
> + machine_mode promoted_mode = ops_mode;
> + tree promoted_type = ops_type;
> + bool is_unsigned = TYPE_UNSIGNED (ops_type);
> +
> + /* Check if spaceship optab is available for the operand mode.
> + If not, try promoting to a wider mode that is supported. */
> + if (optab_handler (spaceship_optab, ops_mode) == CODE_FOR_nothing)
> + {
> + /* Try promoting to wider modes (e.g., QI/HI -> SI -> DI). */
> + machine_mode wider_mode;
> + FOR_EACH_WIDER_MODE_FROM (wider_mode, ops_mode)
> + {
> + if (optab_handler (spaceship_optab, wider_mode)
> + != CODE_FOR_nothing)
> + {
> + /* Check if we can get a type for this mode with matching
> + signedness. */
> + promoted_type = lang_hooks.types.type_for_mode (wider_mode,
> + is_unsigned);
> + if (promoted_type != NULL_TREE && INTEGRAL_TYPE_P
> (promoted_type))
> + {
> + promoted_mode = wider_mode;
> + break;
> + }
> + }
> + }
> +
> + /* If no suitable promoted mode found, give up. */
> + if (promoted_mode == ops_mode)
> + return false;
> + }
> +
> + /* If promotion is needed, insert conversion statements.
> + We must use GIMPLE assignments rather than fold_convert because
> + gimple_call arguments must be valid GIMPLE values (SSA names or
> + constants), not tree expressions. */
> + ops[0] = gimple_convert (gsi, true, GSI_SAME_STMT, UNKNOWN_LOCATION,
> + promoted_type, ops[0]);
> + ops[1] = gimple_convert (gsi, true, GSI_SAME_STMT, UNKNOWN_LOCATION,
> + promoted_type, ops[1]);
> +
> + tree spaceship_arg_3 = is_unsigned ? build_one_cst (integer_type_node)
> + : build_minus_one_cst (integer_type_node);
> +
> + gcall *call = gimple_build_call_internal (IFN_SPACESHIP, 3, ops[0], ops[1],
> + spaceship_arg_3);
> +
> + /* SPACESHIP optab always returns signed int (SI mode).
> + Cast to phi_result's type if needed. */
> + tree call_result_type = integer_type_node;
> + if (!types_compatible_p (TREE_TYPE (phi_result), call_result_type))
> + {
> + tree call_result = make_ssa_name (call_result_type);
> + gimple_call_set_lhs (call, call_result);
> + gsi_insert_before (gsi, call, GSI_SAME_STMT);
> + gassign *cast_stmt = gimple_build_assign (phi_result, NOP_EXPR,
> + call_result);
> + gsi_insert_before (gsi, cast_stmt, GSI_SAME_STMT);
> + }
> + else
> + {
> + 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]:
> @@ -6515,7 +6603,8 @@ math_opts_dom_walker::after_dom_children (basic_block
> bb)
> 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.54.0
>