Modify the mov<mode>cc expander to support conditional floating-point move
based on integer comparison results. The testcase:

double foo (double a, double b, int c) { return c > 0 ? a : b; }

compiles (-O2) to:

foo:
        addi.d  $r3,$r3,-16
        slti    $r12,$r4,1
        st.d    $r12,$r3,8
        ld.b    $r12,$r3,8
        movgr2fr.w      $f2,$r12
        movfr2cf        $fcc0,$f2
        fsel    $f0,$f0,$f1,$fcc0
        addi.d  $r3,$r3,16
        jr      $r1

Setting the cost of moving GR_REGS to FCC_REGS as the true cost can avoid
unnecessary spill code:

        slti    $r4,$r4,1
        movgr2fr.w      $f2,$r4
        movfr2cf        $fcc0,$f2
        fsel    $f0,$f0,$f1,$fcc0
        jr      $r1

gcc/ChangeLog:

        * config/loongarch/loongarch.cc (loongarch_expand_conditional_move):
        Allow conditional move FP via integer condition codes.
        (loongarch_move_to_gpr_cost): Use actual FCC->GPR move cost.
        (loongarch_move_from_gpr_cost): Use actual GPR->FCC move cost.
        (loongarch_secondary_reload): Adjust.
        * config/loongarch/loongarch.md (mov<mode>cc): Adjust.

gcc/testsuite/ChangeLog:

        * gcc.target/loongarch/la64/ifcvt-double-1.c: New test.
        * gcc.target/loongarch/la64/ifcvt-double-2.c: New test.
---
 gcc/config/loongarch/loongarch.cc             | 31 ++++++++++++++++---
 gcc/config/loongarch/loongarch.md             |  3 +-
 .../loongarch/la64/ifcvt-double-1.c           | 11 +++++++
 .../loongarch/la64/ifcvt-double-2.c           | 10 ++++++
 4 files changed, 50 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/la64/ifcvt-double-1.c
 create mode 100644 gcc/testsuite/gcc.target/loongarch/la64/ifcvt-double-2.c

diff --git a/gcc/config/loongarch/loongarch.cc 
b/gcc/config/loongarch/loongarch.cc
index bf401602394..1715b483c96 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -5966,6 +5966,15 @@ loongarch_expand_conditional_move (rtx *operands)
        {
          op0 = loongarch_zero_if_equal (op0, op1);
          op1 = const0_rtx;
+
+         if (FLOAT_MODE_P (mode))
+           {
+             rtx target = gen_reg_rtx (GET_MODE (op0));
+             rtx zero = force_reg (GET_MODE (op0), const0_rtx);
+             loongarch_emit_int_order_test (LTU, NULL, target, zero, op0);
+             op0 = target;
+           }
+
          /* For EQ, set target to 1 if op0 and op1 are the same,
             otherwise set to 0.
             For NE, set target to 0 if op0 and op1 are the same,
@@ -6017,6 +6026,18 @@ loongarch_expand_conditional_move (rtx *operands)
       mode = DImode;
     }
 
+  /* Transfer integer comparison result to fcc.  */
+  if (INTEGRAL_MODE_P (GET_MODE (op0)) && FLOAT_MODE_P (mode))
+    {
+      rtx tmp = op0;
+      op0 = gen_reg_rtx (FCCmode);
+      emit_move_insn (op0, gen_lowpart (FCCmode, tmp));
+      if (code != NE)
+       {
+         std::swap (operands[2], operands[3]);
+         code = NE;
+       }
+    }
   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.  */
@@ -7541,7 +7562,8 @@ loongarch_move_to_gpr_cost (reg_class_t from)
       return 4;
 
     case FCC_REGS:
-      return loongarch_cost->movcf2gr;
+      /* MOVCF2GR or MOVCF2FR + MOVFR2GR.  */
+      return MIN (loongarch_cost->movcf2gr, COSTS_N_INSNS (2));
 
     default:
       return 0;
@@ -7566,7 +7588,8 @@ loongarch_move_from_gpr_cost (reg_class_t to)
       return 4;
 
     case FCC_REGS:
-      return loongarch_cost->movgr2cf;
+      /* MOVGR2CF or MOVGR2FR + MOVFR2CF.  */
+      return MIN (loongarch_cost->movgr2cf, COSTS_N_INSNS (2));
 
     default:
       return 0;
@@ -7652,7 +7675,7 @@ loongarch_secondary_reload (bool in_p ATTRIBUTE_UNUSED, 
rtx x,
          auto fn = in_p ? loongarch_move_from_gpr_cost
                         : loongarch_move_to_gpr_cost;
 
-         if (fn (FCC_REGS) > fn (FP_REGS) + COSTS_N_INSNS (1))
+         if (fn (FCC_REGS) > COSTS_N_INSNS (1))
            return FP_REGS;
 
          return GP_REG_P (regno) ? NO_REGS : GR_REGS;
@@ -7663,7 +7686,7 @@ loongarch_secondary_reload (bool in_p ATTRIBUTE_UNUSED, 
rtx x,
          auto fn = in_p ? loongarch_move_to_gpr_cost
                         : loongarch_move_from_gpr_cost;
 
-         if (fn (FCC_REGS) > fn (FP_REGS) + COSTS_N_INSNS (1))
+         if (fn (FCC_REGS) > COSTS_N_INSNS (1))
            return FP_REGS;
 
          return NO_REGS;
diff --git a/gcc/config/loongarch/loongarch.md 
b/gcc/config/loongarch/loongarch.md
index ceacc5995e6..9cbc4d44956 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -2825,7 +2825,8 @@ (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))))
+  if (!INTEGRAL_MODE_P (GET_MODE (XEXP (operands[1], 0)))
+      && !FLOAT_MODE_P (GET_MODE (XEXP (operands[1], 0))))
     FAIL;
 
   loongarch_expand_conditional_move (operands);
diff --git a/gcc/testsuite/gcc.target/loongarch/la64/ifcvt-double-1.c 
b/gcc/testsuite/gcc.target/loongarch/la64/ifcvt-double-1.c
new file mode 100644
index 00000000000..427e761aaad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/la64/ifcvt-double-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-rtl-ce1" } */
+/* { dg-final { scan-rtl-dump "3 true changes made" "ce1" } } */
+/* { dg-final { scan-assembler "movgr2fr\\.w\t\\\$f\[0-9\]+,\\\$r4" } } */
+/* { dg-final { scan-assembler "movfr2cf\t\\\$fcc0" } } */
+
+double
+foo (double a, double b, int c)
+{
+  return c > 0 ? a : b;
+}
diff --git a/gcc/testsuite/gcc.target/loongarch/la64/ifcvt-double-2.c 
b/gcc/testsuite/gcc.target/loongarch/la64/ifcvt-double-2.c
new file mode 100644
index 00000000000..b7f0866d754
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/la64/ifcvt-double-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-rtl-ce1 -mtune=la664" } */
+/* { dg-final { scan-rtl-dump "3 true changes made" "ce1" } } */
+/* { dg-final { scan-assembler "movgr2cf\t\\\$fcc0,\\\$r4" } } */
+
+double
+foo (double a, double b, int c)
+{
+  return c > 0 ? a : b;
+}
-- 
2.20.1

Reply via email to