* [PATCH v1] LoongArch: Add floating point conditional move support.
@ 2023-09-15 3:33 Lulu Cheng
0 siblings, 0 replies; only message in thread
From: Lulu Cheng @ 2023-09-15 3:33 UTC (permalink / raw)
To: gcc-patches; +Cc: xry111, i, xuchenghua, Lulu Cheng, yala
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 <zhaojunchao@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>")])
+
\f
;; 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
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2023-09-15 3:33 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-15 3:33 [PATCH v1] LoongArch: Add floating point conditional move support Lulu Cheng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).