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