This helps to optimize certain nested ternary operation producing -1, 0,
or 1 to slt[u]-slt[u]-sub.

gcc/

        * config/loongarch/loongarch.md (spaceship<mode>4): New
        define_expand.

gcc/testsuite/

        * gcc.target/loongarch/la64/spaceship.c: New test.
---

Change from v1: use SRP_SIGNED instead of the incorrect
SRP_SIGNED_AND_UNSIGNED.

Bootstrapped and regtested on loongarch64-linux-gnu.  Ok for trunk?

 gcc/config/loongarch/loongarch.md             | 41 ++++++++++
 .../gcc.target/loongarch/la64/spaceship.c     | 79 +++++++++++++++++++
 2 files changed, 120 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/la64/spaceship.c

diff --git a/gcc/config/loongarch/loongarch.md 
b/gcc/config/loongarch/loongarch.md
index 35a53dd0773..32d837d1e2d 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -3823,6 +3823,47 @@ (define_insn "*sle<u>_<X:mode><GPR:mode>"
   [(set_attr "type" "slt")
    (set_attr "mode" "<X:MODE>")])
 
+(define_expand "spaceship<mode>4"
+  [(match_operand:SI   0 "register_operand")
+   (match_operand:QHWD 1 "register_operand")
+   (match_operand:QHWD 2 "reg_or_0_operand")
+   (match_operand:SI   3 "const_int_operand")]
+  ""
+{
+  gcc_assert (operands[3] == const1_rtx || operands[3] == constm1_rtx);
+
+  if (GET_MODE_SIZE (<MODE>mode) < GET_MODE_SIZE (word_mode))
+    {
+      auto extend = (operands[3] == const1_rtx ? ZERO_EXTEND
+                                              : SIGN_EXTEND);
+      for (int i: {1, 2})
+       if (operands[i] != const0_rtx)
+         operands[i] = force_reg (word_mode,
+                                  gen_rtx_fmt_e (extend, word_mode,
+                                                 operands[i]));
+    }
+
+  auto lt_code = (operands[3] == const1_rtx ? LTU : LT);
+  auto gt_code = (operands[3] == const1_rtx ? GTU : GT);
+  rtx lt = gen_rtx_fmt_ee (lt_code, word_mode, operands[1], operands[2]);
+  rtx gt = gen_rtx_fmt_ee (gt_code, word_mode, operands[1], operands[2]);
+
+  gt = force_reg (word_mode, gt);
+  lt = force_reg (word_mode, lt);
+
+  rtx diff = gen_rtx_MINUS (word_mode, gt, lt);
+  if (TARGET_64BIT)
+    {
+      diff = force_reg (DImode, diff);
+      diff = gen_lowpart (SImode, diff);
+      SUBREG_PROMOTED_VAR_P (diff) = 1;
+      SUBREG_PROMOTED_SET (diff, SRP_SIGNED);
+    }
+
+  emit_move_insn (operands[0], diff);
+  DONE;
+})
+
 
 ;;
 ;;  ....................
diff --git a/gcc/testsuite/gcc.target/loongarch/la64/spaceship.c 
b/gcc/testsuite/gcc.target/loongarch/la64/spaceship.c
new file mode 100644
index 00000000000..0c2f891b58a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/la64/spaceship.c
@@ -0,0 +1,79 @@
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#define TEST(T) \
+  int test_##T(T a, T b) \
+    { return (a == b) ? 0 : (a < b) ? -1 : 1; } \
+  int test_u##T(unsigned T a, unsigned T b) \
+    { return (a == b) ? 0 : (a < b) ? -1 : 1; }
+
+TEST(char)
+TEST(short)
+TEST(int)
+TEST(long)
+
+/*
+** test_char:
+**     slt     .*
+**     slt     .*
+**     sub\.d  .*
+**     jr      \$r1
+*/
+
+/*
+** test_uchar:
+**     sltu    .*
+**     sltu    .*
+**     sub\.d  .*
+**     jr      \$r1
+*/
+
+/*
+** test_short:
+**     slt     .*
+**     slt     .*
+**     sub\.d  .*
+**     jr      \$r1
+*/
+
+/*
+** test_ushort:
+**     sltu    .*
+**     sltu    .*
+**     sub\.d  .*
+**     jr      \$r1
+*/
+
+/*
+** test_int:
+**     slt     .*
+**     slt     .*
+**     sub\.d  .*
+**     jr      \$r1
+*/
+
+/*
+** test_uint:
+**     bstrpick\.d     .*,31,0
+**     bstrpick\.d     .*,31,0
+**     sltu    .*
+**     sltu    .*
+**     sub\.d  .*
+**     jr      \$r1
+*/
+
+/*
+** test_long:
+**     slt     .*
+**     slt     .*
+**     sub\.d  .*
+**     jr      \$r1
+*/
+
+/*
+** test_ulong:
+**     sltu    .*
+**     sltu    .*
+**     sub\.d  .*
+**     jr      \$r1
+*/
-- 
2.54.0

Reply via email to