Gentle ping. Thanks, Avinash
On Tue, 2026-02-24 at 21:57 +0530, Avinash Jayakar wrote: > 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); > } >
