Hi,

Following is a patch proposed to fix PR106536. Investigating it, I found
that rs6000 backend did not implement the spaceship operator. So this
patch implements that for power9+.

Bootstrapped and regtested on powerpc64le-linux-gnu with no regressions.
Ok for trunk?

The other issue from this PR seen was certain patterns like
(a > b ? 1 : (a < b ? -1 : 0))
which is another variant of spaceship operator were not optimized.
Probably it has to be canonicalized in match.pd or in the
optimize_spaceship function.

Thanks and regards,
Avinash Jayakar

The spaceship optab was missing in rs6000 backend, which could be easily
done with setb insn in Power ISA 3.0.
This patch adds support for the integer spaceship optab in power9.
Simple code sequences like
(x == y) ? 0 : (x < y ? -1 : 1)
could be easily done using following insns (only unsigned long shown
here):
        cmpld 0,3,4
        setb 3,0
Also improves code generated for <=> operator introduced in C++20.

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

gcc/ChangeLog:
        PR target/106536
        * config/rs6000/rs6000.md (spaceship<mode>4): Add new optab
        implementation.

gcc/testsuite/ChangeLog:
        PR target/106536
        * gcc.target/powerpc/spaceship-int-p9.c: New test.
---
 gcc/config/rs6000/rs6000.md                   | 62 +++++++++++++++++++
 .../gcc.target/powerpc/spaceship-int-p9.c     | 34 ++++++++++
 2 files changed, 96 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/spaceship-int-p9.c

diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 3089551552c..5f839c49e5f 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -15724,6 +15724,68 @@ (define_insn "setb_unsigned"
   "setb %0,%1"
   [(set_attr "type" "logical")])
 
+
+;; Spaceship operator support for PowerPC
+;; Implements three-way comparison: (a <=> b)
+;; Returns: -1 if a < b, 0 if a == b, 1 if a > b
+
+(define_mode_iterator SPACESHIP_INT [DI SI HI QI])
+;; Integer spaceship operator
+(define_expand "spaceship<mode>4"
+  [(match_operand:SI 0 "gpc_reg_operand")
+   (match_operand:SPACESHIP_INT 1 "gpc_reg_operand")
+   (match_operand:SPACESHIP_INT 2 "gpc_reg_operand")
+   (match_operand:SI 3 "const_int_operand")]
+  "TARGET_P9_MISC"
+{
+  bool is_unsigned = (operands[3] == const1_rtx);
+
+  // Power9+: Use setb instruction for efficient three-way comparison
+  rtx cc_reg = gen_reg_rtx (is_unsigned ? CCUNSmode : CCmode);
+  rtx op1, op2;
+
+  /* PowerPC only has SI/DI mode comparisons.
+     For HI/QI modes, we need to extend to SImode first.  */
+  if (<MODE>mode == QImode || <MODE>mode == HImode)
+    {
+      // Extend to SImode for comparison
+      if (is_unsigned)
+       {
+         op1 = gen_reg_rtx (SImode);
+         op2 = gen_reg_rtx (SImode);
+         emit_insn (gen_rtx_SET (op1,
+                                 gen_rtx_ZERO_EXTEND (SImode, operands[1])));
+         emit_insn (gen_rtx_SET (op2,
+                                 gen_rtx_ZERO_EXTEND (SImode, operands[2])));
+       }
+      else
+       {
+         op1 = gen_reg_rtx (SImode);
+         op2 = gen_reg_rtx (SImode);
+         emit_insn (gen_rtx_SET (op1,
+                                 gen_rtx_SIGN_EXTEND (SImode, operands[1])));
+         emit_insn (gen_rtx_SET (op2,
+                                 gen_rtx_SIGN_EXTEND (SImode, operands[2])));
+       }
+    }
+  else
+    {
+      // For SI/DI modes, use directly
+      op1 = operands[1];
+      op2 = operands[2];
+    }
+
+  emit_insn (gen_rtx_SET (cc_reg,
+                         gen_rtx_COMPARE (GET_MODE (cc_reg), op1, op2)));
+
+  if (is_unsigned)
+    emit_insn (gen_setb_unsigned (operands[0], cc_reg));
+  else
+    emit_insn (gen_setb_signed (operands[0], cc_reg));
+
+  DONE;
+})
+
 ;; Test byte within two ranges.
 ;;
 ;; The bytes of operand 1 are organized as xx:xx:xx:vv, where xx
diff --git a/gcc/testsuite/gcc.target/powerpc/spaceship-int-p9.c 
b/gcc/testsuite/gcc.target/powerpc/spaceship-int-p9.c
new file mode 100644
index 00000000000..45192fa7918
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/spaceship-int-p9.c
@@ -0,0 +1,34 @@
+/* { dg-do compile { target powerpc-*-*-* } } */
+/* { dg-options "-O2 -mdejagnu-cpu=power9 -fdump-tree-optimized" } */
+
+/* Check if spaceship optimization was done. */
+/* { dg-final { scan-tree-dump-times {\.SPACESHIP \([^,]+, [^,]+, -1\)} 4 
optimized } } */
+/* { dg-final { scan-tree-dump-times {\.SPACESHIP \([^,]+, [^,]+, 1\)} 5 
optimized } } */
+
+/* cmplw is generated for uchar, char, ushort and uint*/
+/* { dg-final { scan-assembler-times "cmplw" 4 } } */
+/* cmpw is generated for schar, sshort and int*/
+/* { dg-final { scan-assembler-times "cmpw" 3 } } */
+
+/* cmpld and cmpd generated for ulong and slong respectively. */
+/* { dg-final { scan-assembler-times "cmpld" 1 } } */
+/* { dg-final { scan-assembler-times "cmpd" 1 } } */
+
+#define TEST(T, U)             \
+  int test_##U (T x, T y)      \
+  {                            \
+    return (x == y) ? 0 : (x < y ? -1 : 1); \
+  }
+
+TEST(signed char, schar)
+TEST(unsigned char, uchar)
+TEST(char, char)
+
+TEST(short, sshort)
+TEST(unsigned short, ushort)
+
+TEST(int, sint)
+TEST(unsigned int, uint)
+
+TEST(long, slong)
+TEST(unsigned long, ulong)
\ No newline at end of file
-- 
2.51.0

Reply via email to