gcc/ChangeLog:

        * config/loongarch/loongarch-protos.h 
(loongarch_expand_conditional_move):
        Modify the return value type of a function.
        * config/loongarch/loongarch.cc (loongarch_expand_conditional_move): 
Added
        floating point conditional
        transfer implementation code.
        * config/loongarch/loongarch.md (%3,%2): Define new code_attr.
        (@movdgr2fr<mode>): New template.
        (@movdfr2gr<mode>): Likewise.
        (@movfr2fcc<mode>): Likewise.
        (@movgr2fcc<mode>): Likewise.

gcc/testsuite/ChangeLog:

        * gcc.target/loongarch/cmov_ff.c: New test.
        * gcc.target/loongarch/cmov_fi.c: New test.
        * gcc.target/loongarch/cmov_if.c: New test.

Signed-off-by: yala <zhaojunc...@loongson.cn>
---
 gcc/config/loongarch/loongarch-protos.h      |   2 +-
 gcc/config/loongarch/loongarch.cc            | 117 ++++++++++++++++++-
 gcc/config/loongarch/loongarch.md            |  60 ++++++++--
 gcc/testsuite/gcc.target/loongarch/cmov_ff.c |  16 +++
 gcc/testsuite/gcc.target/loongarch/cmov_fi.c |  15 +++
 gcc/testsuite/gcc.target/loongarch/cmov_if.c |  15 +++
 6 files changed, 208 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/cmov_ff.c
 create mode 100644 gcc/testsuite/gcc.target/loongarch/cmov_fi.c
 create mode 100644 gcc/testsuite/gcc.target/loongarch/cmov_if.c

diff --git a/gcc/config/loongarch/loongarch-protos.h 
b/gcc/config/loongarch/loongarch-protos.h
index 251011c5414..5501fb8da97 100644
--- a/gcc/config/loongarch/loongarch-protos.h
+++ b/gcc/config/loongarch/loongarch-protos.h
@@ -100,7 +100,7 @@ extern bool loongarch_cfun_has_cprestore_slot_p (void);
 extern void loongarch_expand_scc (rtx *);
 extern bool loongarch_expand_vec_cmp (rtx *);
 extern void loongarch_expand_conditional_branch (rtx *);
-extern void loongarch_expand_conditional_move (rtx *);
+extern bool loongarch_expand_conditional_move (rtx *);
 extern void loongarch_expand_conditional_trap (rtx);
 #endif
 extern void loongarch_set_return_address (rtx, rtx);
diff --git a/gcc/config/loongarch/loongarch.cc 
b/gcc/config/loongarch/loongarch.cc
index 845fad5a8e8..5aad5058024 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -5063,7 +5063,42 @@ loongarch_expand_conditional_branch (rtx *operands)
 /* Perform the comparison in OPERANDS[1].  Move OPERANDS[2] into OPERANDS[0]
    if the condition holds, otherwise move OPERANDS[3] into OPERANDS[0].  */
 
-void
+/* iiii: means selecting a fixed point based on fixed point comparison result.
+    cmp_code is eq/ne:
+      xor op0 i i
+      maskeqz
+      masknez
+      or
+    cmp_code is not eq/ne:
+      slt[u] op0 i i
+      maskeqz
+      masknez
+      or
+
+   iiff: means Selecting a floating point base on fixed point comparison 
result.
+     cmp_code is eq/ne:
+      xor op0 i i
+      slt[u] op1
+      movdgr2fr f, op1
+      movfr2fcc fcc, f0
+      fsel f, f, f, fcc
+     cmp_code is not eq/ne:
+      slt[u] op0
+      movdgr2fr f, op0
+      movfr2fcc fcc, f
+      fsel f,f,f,fcc
+
+   ffii: means Selecting a fixed point base on floating point comparison 
result.
+      fcmp.cond.{s/d} fcc, f, f
+      movgr2fr f, i
+      movgr2fr f, i
+      fsel f,f,f,fcc
+      movfr2gr i,f
+
+   ffff: means Selecting a floating point base on floating point comparison
+   result.
+      fcmp.cond.{s.d}.  */
+bool
 loongarch_expand_conditional_move (rtx *operands)
 {
   enum rtx_code code = GET_CODE (operands[1]);
@@ -5071,6 +5106,8 @@ loongarch_expand_conditional_move (rtx *operands)
   rtx op1 = XEXP (operands[1], 1);
   rtx op0_extend = op0;
   rtx op1_extend = op1;
+  machine_mode cmp_mode = GET_MODE (op0);
+  machine_mode sel_mode = GET_MODE (operands[2]);
 
   /* Record whether operands[2] and operands[3] modes are promoted to 
word_mode.  */
   bool promote_p = false;
@@ -5097,6 +5134,12 @@ loongarch_expand_conditional_move (rtx *operands)
       if (code == EQ || code == NE)
        {
          op0 = loongarch_zero_if_equal (op0, op1);
+
+         /* Be careful iiff.  */
+         if (FLOAT_MODE_P (sel_mode))
+           loongarch_emit_int_order_test (LTU, NULL, op0,
+                                          force_reg (GET_MODE (op0),
+                                                     const0_rtx), op0);
          op1 = const0_rtx;
        }
       else
@@ -5115,7 +5158,8 @@ loongarch_expand_conditional_move (rtx *operands)
   rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
   /* There is no direct support for general conditional GP move involving
      two registers using SEL.  */
-  if (INTEGRAL_MODE_P (GET_MODE (operands[2]))
+  if (INTEGRAL_MODE_P (cmp_mode)
+      && (INTEGRAL_MODE_P (sel_mode))
       && register_operand (operands[2], VOIDmode)
       && register_operand (operands[3], VOIDmode))
     {
@@ -5165,11 +5209,72 @@ loongarch_expand_conditional_move (rtx *operands)
        }
       else
        emit_insn (gen_rtx_SET (operands[0], gen_rtx_IOR (mode, temp, temp2)));
+
+      return true;
     }
-  else
-    emit_insn (gen_rtx_SET (operands[0],
-                           gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), cond,
-                                                 operands[2], operands[3])));
+  /* For ffii, iiff due to movgr2fr, movfr2gr overhead is relatively large, so
+     we use some compromise.  */
+  else if (INTEGRAL_MODE_P (cmp_mode)
+          && (FLOAT_MODE_P (sel_mode))
+          && register_operand (operands[2], VOIDmode)
+          && register_operand (operands[3], VOIDmode))
+    {
+      rtx temp = gen_reg_rtx (sel_mode);
+      rtx fcc_reg = loongarch_allocate_fcc (FCCmode);
+      rtx diop0 = convert_to_mode (E_DImode, op0, true);
+
+      /* stl t0 i i-> movgr2fr f0 t0 -> movfr2cf fcc0 f0 -> fsel f f.  */
+      emit_insn (gen_movdgr2fr (sel_mode, temp, diop0));
+      emit_insn (gen_movfr2fcc (sel_mode, fcc_reg, temp));
+
+      cond = gen_rtx_fmt_ee (code, GET_MODE (fcc_reg), fcc_reg, const0_rtx);
+
+      emit_insn (gen_rtx_SET (operands[0],
+                             gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+                                                   cond, operands[2],
+                                                   operands[3])));
+      return true;
+    }
+  else if (FLOAT_MODE_P (cmp_mode) && (INTEGRAL_MODE_P (sel_mode)))
+    {
+      /* movgr2fr f0 i -> movgr2fr f1 i -> fcmp fcc0 f f
+        -> fsel f3 f0 f1 -> movfr2gr t0 f3.  */
+      machine_mode dst_mode = GET_MODE (operands[0]);
+      rtx temp = gen_reg_rtx (E_DFmode);
+      rtx temp2 = gen_reg_rtx (E_DFmode);
+      rtx temp3 = gen_reg_rtx (E_DFmode);
+
+      if (CONST_INT_P (operands[2]))
+       operands[2] = copy_to_mode_reg (dst_mode, operands[2]);
+
+      if (CONST_INT_P (operands[3]))
+       operands[3] = copy_to_mode_reg (dst_mode, operands[3]);
+
+      if (GET_MODE (operands[2]) != E_DImode)
+       operands[2] = convert_to_mode (E_DImode, operands[2], false);
+
+      if (GET_MODE (operands[3]) != E_DImode)
+       operands[3] = convert_to_mode (E_DImode, operands[3], false);
+
+      emit_insn (gen_movdgr2frdf (temp2, operands[2]));
+      emit_insn (gen_movdgr2frdf (temp3, operands[3]));
+      emit_insn (gen_rtx_SET (temp,
+                             gen_rtx_IF_THEN_ELSE (E_DFmode, cond,
+                                                   temp2, temp3)));
+      emit_insn (gen_movdfr2gr (GET_MODE (operands[0]), operands[0], temp));
+
+      return true;
+    }
+  else if (FLOAT_MODE_P (cmp_mode) && FLOAT_MODE_P (sel_mode))
+    {
+      emit_insn (gen_rtx_SET (operands[0],
+                             gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+                                                   cond, operands[2],
+                                                   operands[3])));
+      return true;
+    }
+
+  return false;
 }
 
 /* Implement TARGET_EXPAND_BUILTIN_VA_START.  */
diff --git a/gcc/config/loongarch/loongarch.md 
b/gcc/config/loongarch/loongarch.md
index 4fcb6d781d5..158480ca2a4 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -30,7 +30,12 @@ (define_c_enum "unspec" [
   UNSPEC_LOAD_HIGH
   UNSPEC_STORE_WORD
   UNSPEC_MOVGR2FRH
+  UNSPEC_MOVGR2FR
   UNSPEC_MOVFRH2GR
+  UNSPEC_MOVFR2GR
+  UNSPEC_MOVFCC2GR
+  UNSPEC_MOVGR2FCC
+  UNSPEC_MOVFR2FCC
 
   ;; Floating point unspecs.
   UNSPEC_FRINT
@@ -295,6 +300,7 @@ (define_attr "type"
 ;; D2I float to integer (DF to SI/DI)
 ;; D2S double to float single
 ;; S2D float single to double
+;; C2D  fcc to DI
 
 (define_attr "cnv_mode" "unknown,I2S,I2D,S2I,D2I,D2S,S2D"
   (const_string "unknown"))
@@ -559,6 +565,7 @@ (define_code_attr fcond [(unordered "cun")
 
 ;; The sel mnemonic to use depending on the condition test.
 (define_code_attr sel [(eq "masknez") (ne "maskeqz")])
+(define_code_attr fsel_invert [(eq "%2,%3") (ne "%3,%2")])
 (define_code_attr selinv [(eq "maskeqz") (ne "masknez")])
 
 ;; Iterator and attributes for floating-point to fixed-point conversion
@@ -2178,12 +2185,12 @@ (define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
 (define_insn "*sel<mode>"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
        (if_then_else:ANYF
-        (ne:FCC (match_operand:FCC 1 "register_operand" "z")
+        (equality_op:FCC (match_operand:FCC 1 "register_operand" "z")
                 (const_int 0))
         (match_operand:ANYF 2 "reg_or_0_operand" "f")
         (match_operand:ANYF 3 "reg_or_0_operand" "f")))]
   ""
-  "fsel\t%0,%3,%2,%1"
+  "fsel\t%0,<fsel_invert>,%1"
   [(set_attr "type" "condmove")
    (set_attr "mode" "<ANYF:MODE>")])
 
@@ -2196,11 +2203,10 @@ (define_expand "mov<mode>cc"
                          (match_operand:GPR 3 "reg_or_0_operand")])))]
   "TARGET_COND_MOVE_INT"
 {
-  if (!INTEGRAL_MODE_P (GET_MODE (XEXP (operands[1], 0))))
+  if (loongarch_expand_conditional_move (operands))
+    DONE;
+  else
     FAIL;
-
-  loongarch_expand_conditional_move (operands);
-  DONE;
 })
 
 (define_expand "mov<mode>cc"
@@ -2210,11 +2216,11 @@ (define_expand "mov<mode>cc"
                           (match_operand:ANYF 3 "reg_or_0_operand")])))]
   "TARGET_COND_MOVE_FLOAT"
 {
-  if (!FLOAT_MODE_P (GET_MODE (XEXP (operands[1], 0))))
-    FAIL;
 
-  loongarch_expand_conditional_move (operands);
-  DONE;
+  if (loongarch_expand_conditional_move (operands))
+    DONE;
+  else
+    FAIL;
 })
 
 (define_insn "lu32i_d"
@@ -2447,6 +2453,15 @@ (define_insn "movgr2frh<mode>"
   [(set_attr "move_type" "mgtf")
    (set_attr "mode" "<HALFMODE>")])
 
+(define_insn "@movdgr2fr<mode>"
+  [(set (match_operand:ANYF 0 "register_operand" "=f")
+       (unspec:ANYF [(match_operand:DI 1 "register_operand" "r")]
+                       UNSPEC_MOVGR2FR))]
+  "TARGET_DOUBLE_FLOAT"
+  "movgr2fr.d\t%0,%1"
+  [(set_attr "move_type" "mgtf")
+   (set_attr "mode" "<MODE>")])
+
 ;; Move high word of operand 1 to operand 0 using movfrh2gr.s.
 (define_insn "movfrh2gr<mode>"
   [(set (match_operand:<HALFMODE> 0 "register_operand" "=r")
@@ -2457,6 +2472,31 @@ (define_insn "movfrh2gr<mode>"
   [(set_attr "move_type" "mftg")
    (set_attr "mode" "<HALFMODE>")])
 
+(define_insn "@movdfr2gr<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+       (unspec:GPR [(match_operand:DF 1 "register_operand" "f")]
+                           UNSPEC_MOVFR2GR))]
+  "TARGET_DOUBLE_FLOAT"
+  "movfr2gr.d\t%0,%1"
+  [(set_attr "move_type" "mftg")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "@movfr2fcc<mode>"
+  [(set (match_operand:FCC 0 "register_operand" "=z")
+       (unspec:FCC [(match_operand:ANYF 1 "register_operand" "f")]
+                           UNSPEC_MOVFR2FCC))]
+  "TARGET_HARD_FLOAT"
+  "movfr2cf\t%0,%1"
+  [(set_attr "mode" "<MODE>")])
+
+(define_insn "@movgr2fcc<mode>"
+  [(set (match_operand:FCC 0 "register_operand" "=z")
+       (unspec:FCC [(match_operand:GPR 1 "register_operand" "r")]
+                           UNSPEC_MOVGR2FCC))]
+  "TARGET_HARD_FLOAT"
+  "movgr2cf\t%0,%1"
+  [(set_attr "mode" "<MODE>")])
+
 
 ;; Expand in-line code to clear the instruction cache between operand[0] and
 ;; operand[1].
diff --git a/gcc/testsuite/gcc.target/loongarch/cmov_ff.c 
b/gcc/testsuite/gcc.target/loongarch/cmov_ff.c
new file mode 100644
index 00000000000..c49a20f23a7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/cmov_ff.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdouble-float" } */
+/* { dg-final { scan-assembler "test:.*fcmp.*fsel.*" } } */
+
+extern void foo_ff (float *, float *, float *, float *);
+
+float
+test (void)
+{
+  float a, b;
+  float c, d, out;
+  foo_ff (&a, &b, &c, &d);
+  out = a > b ? c : d;
+  return out;
+}
+
diff --git a/gcc/testsuite/gcc.target/loongarch/cmov_fi.c 
b/gcc/testsuite/gcc.target/loongarch/cmov_fi.c
new file mode 100644
index 00000000000..07838dad748
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/cmov_fi.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdouble-float" } */
+/* { dg-final { scan-assembler "test:.*movgr2fr.*movgr2fr.*fsel.*movfr2gr.*" } 
} */
+
+extern void foo_fi (float *, float *, int *, int *);
+
+int
+test (void)
+{
+  float a, b;
+  int c, d, out;
+  foo_fi (&a, &b, &c, &d);
+  out = a > b ? c : d;
+  return out;
+}
diff --git a/gcc/testsuite/gcc.target/loongarch/cmov_if.c 
b/gcc/testsuite/gcc.target/loongarch/cmov_if.c
new file mode 100644
index 00000000000..8da11bc90a6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/cmov_if.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdouble-float" } */
+/* { dg-final { scan-assembler "test:.*movfr2cf.*fsel.*" } } */
+
+extern void foo_if (int *, int *, float *, float *);
+
+float
+test (void)
+{
+  int a, b;
+  float c, d, out;
+  foo_if (&a, &b, &c, &d);
+  out = a == b ? c : d;
+  return out;
+}
-- 
2.31.1

Reply via email to