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