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